Linux代码版本:linux3.0
开发板环境: tiny4412
导读:前面先后分析了kset、kobject、bus和class,其中在bus和class的代码之中已经展示了对kobject和kset的应用,而bus和class中的一些结构体成员并没有涉及,在device和driver的注册过程中,将会展示一些成员的用途。
一、device结构体
linux中有各种各样的设备,不同的设备有不同的属性,但是这些设备又有一些共同点,所以device结构体所谓所有类型设备的基类,然后再根据不同的设备封装不同的结构体。下面将介绍device和platform_device结构体,然后分析一个i2c控制器的注册过程。
struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
const struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
struct dev_power_domain *pwr_domain;
#ifdef CONFIG_NUMA
int numa_node; /* NUMA node this device is close to */
#endif
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
#ifdef CONFIG_DMA_CMA
struct cma *cma_area; /* contiguous memory area for dma
allocation */
#endif
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
struct device *parent;
device的父设备
struct device_private *p;
device的私有结构体
struct kobject kobj;
device封装的kobj,bus,kset和class最终也都封装了kobject
const char *init_name; /* initial name of the device */
device初始化的名字
const struct device_type *type;
device的类型如partitions、disks和mouse等
struct mutex mutex; /* mutex to synchronize calls to * its driver. */
信号量,操作结构体成员时使用
struct bus_type *bus; /* type of bus device is on */
挂接的bus类型
struct device_driver *driver; /* which driver has allocated thisdevice */
该device对应的driver
void *platform_data; /* Platform specific data, device core doesn't touch it */
platform使用的特殊数据
struct dev_pm_info power;
电源管理相关
struct dev_power_domain *pwr_domain;
电源管理相关
struct device_node *of_node; /* associated device tree node */
device tree相关的node
dev_t devt; /* dev_t, creates the sysfs "dev" */
设备号
struct klist_node knode_class;
用于挂接在class的链表
struct class *class;
device所属的class
const struct attribute_group **groups; /* optional groups */
属性组,用于创建属性属性文件
void (*release)(struct device *dev);
释放device结构体的时候使用
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
const char * name:
设备名字
int id:
设备id号,只有一个此类设备的话设置-1,多个有同类设备在创建设备目录的时候会带上此id号
struct device dev:
封装的device结构体;
u32 num_resources;
所占用的resources的个数
struct resource * resource:
所占用的resource,如IORESOURCE_MEM和IORESOURCE_IRQ等
const struct platform_device_id *id_entry:
和驱动中的id_table相关,当通过驱动 id_table 匹配上时,将匹配到的id_table赋值给id_entry,暂时不知道实际用途
遇到的时候再分析
二、platform_device实例
虽然i2c本身也是一种总线,但是其也挂接在platform总线上。因为重点是platform_device的注册过程,所以对涉及i2c的一些细节不再分析(如硬件资源)。下面的代码还是原始在plat和mach中声明platform_device形式,device tree的形式等分析device tree的时候再详细看。
struct platform_device s3c_device_i2c3 = {
.name = "s3c2440-i2c",
.id = 3,
.num_resources = ARRAY_SIZE(s3c_i2c_resource),
.resource = s3c_i2c_resource,
};
static struct platform_device *torbreck_devices[] __initdata = {
&s5pv210_device_iis0,
&s3c_device_cfcon,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
&s3c_device_i2c0,
&s3c_device_i2c3,
&s3c_device_i2c4,
&s3c_device_rtc,
&s3c_device_wdt,
};
&s3c_device_i2c3,
&s3c_device_i2c4,
&s3c_device_rtc,
&s3c_device_wdt,
};
static void __init torbreck_machine_init(void)
{
.......
platform_add_devices(torbreck_devices, ARRAY_SIZE(torbreck_devices));
}
platform_add_devices(torbreck_devices, ARRAY_SIZE(torbreck_devices));
}
将上面的过程简化 就是
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
{
/**初始化 s3c_device_i2c3->dev->kobj.kset = devices_kset,还记得sys下的deivces目录吗
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);*/
dev->kobj.kset = devices_kset;
/*初始化 s3c_device_i2c3->dev->kobj->ktype = &device_ktype,device设备kobj类型为device_ktype,
还记得 device_uevent_ops 中的filter 函数过判断此类型吗*/
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 platform_device_add(pdev);
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
/*初始化s3c_device_i2c3->dev.parent 为 platform_bus,
意味着device对应的目录会在 sys/devices/platform下*/
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
/*挂接在platform总线上*/
pdev->dev.bus = &platform_bus_type;
/*看结构体定义s3c_device_i2c3->id = 3,所以pdev->dev->kobj->name = "s3c2440-i2c.3"
如果系统里只有一个此类设备,id初始化为 -1就行了*/
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, "%s", pdev->name);
/*下面就是将 s3c_device_i2c3.resource插入到 reourse tree,
插入的时候会做冲突检查*/
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
/*插入到 resource tree的时候如果检查到 recourse 已被插入过,说明resource冲突,
一个硬件资源不能同时分给多个设备用,不然会出错*/
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->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);
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()
*/
/*s3c_device_i2c3->dev->init_name未赋值,也就是为NULL*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
/*s3c_device_i2c3->dev->name 定义时初始化为 "s3c2410-i2c"*/
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
/*前面初始化s3c_device_i2c3->dev->parent = &platform_bus*/
parent = get_device(dev->parent);
/*device层面的parent已经建立,setup_parent要建立kobject 层面的关系*/
setup_parent(dev, parent);
{
struct kobject *kobj;
/*执行结果kobj = &parent->kobj*/
kobj = get_device_parent(dev, parent);
{
/*s3c_device_i2c3->dev->class未初始化,所以为NULL,
等后面分析device_creat的时候再详细分析此函数*/
if (dev->class) {
......
}
if (parent)
return &parent->kobj;
return NULL;
}
/*赋值结果 s3c_device_i2c3->dev->kobj->parent = platform_bus->kobj*/
if (kobj)
dev->kobj.parent = kobj;
}
/* use parent numa_node */
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*/
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.3创建uevent文件*/
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
/*此时s3c_device_i2c3->dev还没有设备号,所以执行不到,等到device_creat的时候再详细分析*/
if (MAJOR(dev->devt)) {
......
}
/*在class下创建链接*/
error = device_add_class_symlinks(dev);
{
int error;
/*s3c_device_i2c3->dev->class未赋值,也就是为NULL,在此返回*/
if (!dev->class)
return 0;
......
}
if (error)
goto SymlinkError;
/*为s3c_device_i2c3->dev穿件属性文件*/
error = device_add_attrs(dev);
{
struct class *class = dev->class;
const struct device_type *type = dev->type;
int error;
/*s3c_device_i2c3->dev->class未赋值,也就是为NULL,在此返回*/
if (class) {
......
}
/* s3c_device_i2c3->dev-type 未赋值,所以为NULL*/
if (type) {
......
}
/*s3c_device_i2c3->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;
/*将device挂接到bus上去,并创建一些属性文件*/
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;
/*结构体定义时就初始化为platform_bus_type->dev_attrs = platform_dev_attrs
platform_dev_attrs.name = "modalias",也就是会在/sys/devices/platform/s3c2440-i2c.3
创建一个modalias属性文件*/
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;
/*还记得cd /sys/bus//platform/devices 吗
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
下面就是要在/sys/bus//platform/devices创建指向 /sys/devices/platform/s3c2440-i2c.3
的链接,名字也为s3c2440-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创建指向/sys/bus//platform/的链接,
名字为subsystem*/
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
/*将s3c_device_i2c3加入到platform_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;
/*还记得赋值platform_bus_type->p->drivers_autoprobe = 1
跟/sys/bus/platform下的drivers_autoprobe文件吗,drivers_autoprobe被置1
则自动进行驱动匹配*/
if (bus && bus->p->drivers_autoprobe) {
ret = device_attach(dev);
{
int ret = 0;
device_lock(dev);
/*现在只是注册s3c_device_i2c3,还没有匹配驱动,所以 s3c_device_i2c3->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函数逐个匹配platform_bus_type->p->klist_drivers成员
也说明了device_drivver会挂接在platform_bus_type->p->klist_drivers*/
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
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就是__device_attach
{
struct device *dev = data;
/*这就调用到传说中的match函数了,在此调用到的是platform_match,在此由于还未
注册驱动,所以是匹配不到的*/
if (!driver_match_device(drv, dev))
{
/*drv->bus->match就是platform_bus_type->match = platform_match*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* Attempt an OF style match first */
/*先进行device tree风格的匹配,到device tree的时候再详细分析*/
if (of_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
/*再进行id_table形式的匹配,后面device_driver再详细分析id_table*/
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
/*这就是最原始的比较device和driver的名字*/
return (strcmp(pdev->name, drv->name) == 0);
}
}
return 0;
/*如果匹配到驱动,最终会调用到注册driver中的probe函数
后面注册driver的时候再详细分析*/
return driver_probe_device(drv, dev);
}
klist_iter_exit(&i);
return error;
}
pm_runtime_put_sync(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
WARN_ON(ret < 0);
}
}
if (parent)
/*将s3c_device_i2c3加入platform_bus的子设备链表*/
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
/*将s3c_device_i2c3加入到class的设备链表中*/
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);
/*暂时还没弄清class_interface的具体用途*/
/* notify any interfaces that the device is here */
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 (ret == 0)
return ret;
failed:
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
return ret;
}
}
device_initialize(&pdev->dev);
{
/**初始化 s3c_device_i2c3->dev->kobj.kset = devices_kset,还记得sys下的deivces目录吗
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);*/
dev->kobj.kset = devices_kset;
/*初始化 s3c_device_i2c3->dev->kobj->ktype = &device_ktype,device设备kobj类型为device_ktype,
还记得 device_uevent_ops 中的filter 函数过判断此类型吗*/
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 platform_device_add(pdev);
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
/*初始化s3c_device_i2c3->dev.parent 为 platform_bus,
意味着device对应的目录会在 sys/devices/platform下*/
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
/*挂接在platform总线上*/
pdev->dev.bus = &platform_bus_type;
/*看结构体定义s3c_device_i2c3->id = 3,所以pdev->dev->kobj->name = "s3c2440-i2c.3"
如果系统里只有一个此类设备,id初始化为 -1就行了*/
if (pdev->id != -1)
dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id);
else
dev_set_name(&pdev->dev, "%s", pdev->name);
/*下面就是将 s3c_device_i2c3.resource插入到 reourse tree,
插入的时候会做冲突检查*/
for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
p = r->parent;
if (!p) {
if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
/*插入到 resource tree的时候如果检查到 recourse 已被插入过,说明resource冲突,
一个硬件资源不能同时分给多个设备用,不然会出错*/
if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d\n",
dev_name(&pdev->dev), i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s\n",
dev_name(&pdev->dev), dev_name(pdev->dev.parent));
ret = device_add(&pdev->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);
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()
*/
/*s3c_device_i2c3->dev->init_name未赋值,也就是为NULL*/
if (dev->init_name) {
dev_set_name(dev, "%s", dev->init_name);
dev->init_name = NULL;
}
/*s3c_device_i2c3->dev->name 定义时初始化为 "s3c2410-i2c"*/
if (!dev_name(dev)) {
error = -EINVAL;
goto name_error;
}
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
/*前面初始化s3c_device_i2c3->dev->parent = &platform_bus*/
parent = get_device(dev->parent);
/*device层面的parent已经建立,setup_parent要建立kobject 层面的关系*/
setup_parent(dev, parent);
{
struct kobject *kobj;
/*执行结果kobj = &parent->kobj*/
kobj = get_device_parent(dev, parent);
{
/*s3c_device_i2c3->dev->class未初始化,所以为NULL,
等后面分析device_creat的时候再详细分析此函数*/
if (dev->class) {
......
}
if (parent)
return &parent->kobj;
return NULL;
}
/*赋值结果 s3c_device_i2c3->dev->kobj->parent = platform_bus->kobj*/
if (kobj)
dev->kobj.parent = kobj;
}
/* use parent numa_node */
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*/
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.3创建uevent文件*/
error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
/*此时s3c_device_i2c3->dev还没有设备号,所以执行不到,等到device_creat的时候再详细分析*/
if (MAJOR(dev->devt)) {
......
}
/*在class下创建链接*/
error = device_add_class_symlinks(dev);
{
int error;
/*s3c_device_i2c3->dev->class未赋值,也就是为NULL,在此返回*/
if (!dev->class)
return 0;
......
}
if (error)
goto SymlinkError;
/*为s3c_device_i2c3->dev穿件属性文件*/
error = device_add_attrs(dev);
{
struct class *class = dev->class;
const struct device_type *type = dev->type;
int error;
/*s3c_device_i2c3->dev->class未赋值,也就是为NULL,在此返回*/
if (class) {
......
}
/* s3c_device_i2c3->dev-type 未赋值,所以为NULL*/
if (type) {
......
}
/*s3c_device_i2c3->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;
/*将device挂接到bus上去,并创建一些属性文件*/
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;
/*结构体定义时就初始化为platform_bus_type->dev_attrs = platform_dev_attrs
platform_dev_attrs.name = "modalias",也就是会在/sys/devices/platform/s3c2440-i2c.3
创建一个modalias属性文件*/
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;
/*还记得cd /sys/bus//platform/devices 吗
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
下面就是要在/sys/bus//platform/devices创建指向 /sys/devices/platform/s3c2440-i2c.3
的链接,名字也为s3c2440-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创建指向/sys/bus//platform/的链接,
名字为subsystem*/
error = sysfs_create_link(&dev->kobj,
&dev->bus->p->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
/*将s3c_device_i2c3加入到platform_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;
/*还记得赋值platform_bus_type->p->drivers_autoprobe = 1
跟/sys/bus/platform下的drivers_autoprobe文件吗,drivers_autoprobe被置1
则自动进行驱动匹配*/
if (bus && bus->p->drivers_autoprobe) {
ret = device_attach(dev);
{
int ret = 0;
device_lock(dev);
/*现在只是注册s3c_device_i2c3,还没有匹配驱动,所以 s3c_device_i2c3->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函数逐个匹配platform_bus_type->p->klist_drivers成员
也说明了device_drivver会挂接在platform_bus_type->p->klist_drivers*/
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
{
struct klist_iter i;
struct device_driver *drv;
int error = 0;
if (!bus)
return -EINVAL;
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就是__device_attach
{
struct device *dev = data;
/*这就调用到传说中的match函数了,在此调用到的是platform_match,在此由于还未
注册驱动,所以是匹配不到的*/
if (!driver_match_device(drv, dev))
{
/*drv->bus->match就是platform_bus_type->match = platform_match*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
/* Attempt an OF style match first */
/*先进行device tree风格的匹配,到device tree的时候再详细分析*/
if (of_driver_match_device(dev, drv))
return 1;
/* Then try to match against the id table */
/*再进行id_table形式的匹配,后面device_driver再详细分析id_table*/
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
/* fall-back to driver name match */
/*这就是最原始的比较device和driver的名字*/
return (strcmp(pdev->name, drv->name) == 0);
}
}
return 0;
/*如果匹配到驱动,最终会调用到注册driver中的probe函数
后面注册driver的时候再详细分析*/
return driver_probe_device(drv, dev);
}
klist_iter_exit(&i);
return error;
}
pm_runtime_put_sync(dev);
}
out_unlock:
device_unlock(dev);
return ret;
}
WARN_ON(ret < 0);
}
}
if (parent)
/*将s3c_device_i2c3加入platform_bus的子设备链表*/
klist_add_tail(&dev->p->knode_parent,
&parent->p->klist_children);
/*将s3c_device_i2c3加入到class的设备链表中*/
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);
/*暂时还没弄清class_interface的具体用途*/
/* notify any interfaces that the device is here */
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 (ret == 0)
return ret;
failed:
while (--i >= 0) {
struct resource *r = &pdev->resource[i];
unsigned long type = resource_type(r);
if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
return ret;
}
}
从paltform_device注册可以 看出,实际没有做多少工作,还有好多工作没做,比如因class为NULL部分代码执行不到,以及因没有设备号也有一些工作没做。下面进入设备看下整个过程建立的目录、文件和链接。
1. 在sys/devices/platform下创建s3c2440-i2c.3
[root@FriendlyARM rtc0]# cd /sys/devices/platform/
[root@FriendlyARM platform]# ls
alarm s3c2440-i2c.3 samsung-audio
......
s3c2440-i2c.3 samsung-audio
......
2. 在sys/devices/platform/s3c2440-i2c.3创建uevent文件
[root@FriendlyARM platform]# cd s3c2440-i2c.3/
[root@FriendlyARM s3c2440-i2c.3]# ls
driver i2c-3 modalias power subsystem uevent
uevent
3. 在/sys/devices/platform/s3c2440-i2c.3创建一个modalias属性文件
[root@FriendlyARM platform]# cd s3c2440-i2c.3/
[root@FriendlyARM s3c2440-i2c.3]# ls
driver i2c-3 modalias power subsystem uevent
modalias power subsystem uevent
4. 在/sys/bus/platform/devices创建指向 /sys/devices/platform/s3c2440-i2c.3 的链接,名字也为s3c2440-i2c.3*/
[root@FriendlyARM s3c-i2c]# cd /sys/bus/platform/devices/
[root@FriendlyARM devices]# ls -l
......
lrwxrwxrwx 1 root root 0 Jan 1 13:18 s3c2440-i2c.3 -> ../../../devices/platform/s3c2440-i2c.3
......
s3c2440-i2c.3 -> ../../../devices/platform/s3c2440-i2c.3
......
5. 在/sys/devices/platform/s3c2440-i2c.3创建指向/sys/bus/platform/的链接,名字为subsystem
[root@FriendlyARM s3c2440-i2c.3]# cd /sys/devices/platform/s3c2440-i2c.3
[root@FriendlyARM s3c2440-i2c.3]# ls
driver i2c-3 modalias power subsystem uevent
subsystem uevent
对于uevent和modalias属性文件,可以通过其store和show函数看其功能,下面只展示一下modalias属性的定义
static struct device_attribute platform_dev_attrs[] = {
.attr = {
.name = “modalias”,
.mode = 0444
},
.show = modalias_show,
};
除了一句打印,没有其它作用。
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
char *buf)
{
struct platform_device *pdev = to_platform_device(dev);
int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
}
三、platform_driver实例
上面是platform_device的实例,下面就分析platform_driver实例,看看实际的driver如何和device匹配的,上面是s3c_device_i2c3的注册,下面就分析其对应的s3c24xx_i2c_driver为例。
先看 platform_driver 结构体
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
platform_driver比较简单,看名字也比较好理解,只关注
const struct platform_device_id *id_table;
驱动兼容的 device 列表,表明此驱动都可用于哪些device,总线的match会用到这个进行匹配
再看
struct device_driver {
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
const char *name;
驱动的name
struct bus_type *bus;
指向的bus
struct module *owner;
所属的模块,绝大多数情况为 THIS_MODULE,如果不将此驱动编译成模块则为NULL
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
决定是否在/sys/bus/platform/drivers/s3c-i2c下生成 bind 和 ubind 文件
const struct of_device_id *of_match_table;
在总线的 match 函数中用于device tree形式的匹配
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
电源管理相关
struct driver_private *p;
封装的私有结构体。还记得devce、class和bus_type中都有封装私有结构体吗
s3c24xx_i2c_driver实例
static struct platform_driver s3c24xx_i2c_driver = {
.probe = s3c24xx_i2c_probe,
.remove = s3c24xx_i2c_remove,
.id_table = s3c24xx_driver_ids,
.driver = {
.owner = THIS_MODULE,
.name = "s3c-i2c",
.pm = S3C24XX_DEV_PM_OPS,
},
};
看兼容的设备列表
static struct platform_device_id s3c24xx_driver_ids[] = {
{
.name = "s3c2410-i2c",
.driver_data = TYPE_S3C2410,
}, {
.name = "s3c2440-i2c",
.driver_data = TYPE_S3C2440,
}, {
.name = "s3c2440-hdmiphy-i2c",
.driver_data = TYPE_S3C2440_HDMIPHY,
}, { },
};
下面看注册过程:
static int __init i2c_adap_s3c_init(void)
{
return platform_driver_register(&s3c24xx_i2c_driver);
{
drv->driver.bus = &platform_bus_type;
/*s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe
s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove*/
if (drv->probe)
drv->driver.probe = platform_drv_probe;
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
/*最终还是调用的s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe*/
return drv->probe(dev);
}
if (drv->remove)
drv->driver.remove = platform_drv_remove;
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
/*最终还是调用的s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove*/
return drv->remove(dev);
/*s3c24xx_i2c_driver.shutdown = NULL*/ }
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
/*注册driver*/
return driver_register(&drv->driver);
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
/*platform_bus_type->probe = NULL
platform_bus_type->remove = NULL
platform_bus_type->shutdown = NULL
s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe
s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove
s3c24xx_i2c_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;
}
/*如果已经注册过此driver,打印错误信息并返回EBUSY*/
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;
/*前面初始化 s3c24xx_i2c_driver->driver.bus = &platform_bus_type*/
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
/*为s3c24xx_i2c_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;
/*s3c24xx_i2c_driver->driver->priv->kobj.kset = platform_bus_type->p->drivers_kset
还记得sys/bus/platform下的drivers目录吗
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);*/
priv->kobj.kset = bus->p->drivers_kset;
/*在sys/bus/platform/drivers目录下创建s3c-i2c的目录*/
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
/*又见到了drivers_autoprobe,还记得/sys/bus/platform下的drivers_autoprobe文件吗
platform_bus_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注册的时候就是挂接到 platform_bus_type->p->klist_devices
下面就是遍历platform_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 = platform_match,最终还是调用到platform的match函数
最终会匹配到 s3c_device_i2c3*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
return 0;
/*dev = s3c_device_i2c3->dev
s3c_device_i2c3->dev->parent = &platform_bus */
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/platform/drivers/s3c-i2c创建指向s3c2440-i2c.3的链接,
名字仍然为s3c2440-i2c.3*/
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
/*在sys/bus/platform/device/s3c2440-i2c.3下
创建指向sys/bus/platform/drivers/s3c-i2c的链接,名字为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;
}
/*platform_bus_type->probe = NULL,所以调用
s3c24xx_i2c_driver->probe也就是 s3c24xx_i2c_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);
{ /*前面s3c_device_i2c3->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;
}
/*将s3c24xx_i2c_driver挂接在platform的driver链表中*/
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
/*在/sys/bus/platform/drivers/s3c-i2c创建uevent文件*/
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
/*为 s3c24xx_i2c_driver 创建默认的属性文件,可是platform_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);
}
/*s3c24xx_i2c_driver->drv->suppress_bind_attrs 未赋值,也就是为0*/
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
{
int ret;
/*在/sys/bus/platform/drivers/s3c-i2c目录下创建 ubind 文件*/
ret = driver_create_file(drv, &driver_attr_unbind);
if (ret == 0) {
/*在/sys/bus/platform/drivers/s3c-i2c目录下创建 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;
/*创建属性组及文件,s3c24xx_i2c_driver->drv未初始化,也就是为NULL,不会创建任何文件*/
ret = driver_add_groups(drv, drv->groups);
{
int error = 0;
int i;
if (groups) {
for (i = 0; groups[i]; i++) {
error = sysfs_create_group(&drv->p->kobj, groups[i]);
if (error) {
while (--i >= 0)
sysfs_remove_group(&drv->p->kobj,
groups[i]);
break;
}
}
}
return error;
}
if (ret)
bus_remove_driver(drv);
return ret;
}
}
}
{
drv->driver.bus = &platform_bus_type;
/*s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe
s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove*/
if (drv->probe)
drv->driver.probe = platform_drv_probe;
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
/*最终还是调用的s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe*/
return drv->probe(dev);
}
if (drv->remove)
drv->driver.remove = platform_drv_remove;
{
struct platform_driver *drv = to_platform_driver(_dev->driver);
struct platform_device *dev = to_platform_device(_dev);
/*最终还是调用的s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove*/
return drv->remove(dev);
/*s3c24xx_i2c_driver.shutdown = NULL*/ }
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
/*注册driver*/
return driver_register(&drv->driver);
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
/*platform_bus_type->probe = NULL
platform_bus_type->remove = NULL
platform_bus_type->shutdown = NULL
s3c24xx_i2c_driver->probe = s3c24xx_i2c_probe
s3c24xx_i2c_driver->remove = s3c24xx_i2c_remove
s3c24xx_i2c_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;
}
/*如果已经注册过此driver,打印错误信息并返回EBUSY*/
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;
/*前面初始化 s3c24xx_i2c_driver->driver.bus = &platform_bus_type*/
bus = bus_get(drv->bus);
if (!bus)
return -EINVAL;
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
/*为s3c24xx_i2c_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;
/*s3c24xx_i2c_driver->driver->priv->kobj.kset = platform_bus_type->p->drivers_kset
还记得sys/bus/platform下的drivers目录吗
priv->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj);*/
priv->kobj.kset = bus->p->drivers_kset;
/*在sys/bus/platform/drivers目录下创建s3c-i2c的目录*/
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
/*又见到了drivers_autoprobe,还记得/sys/bus/platform下的drivers_autoprobe文件吗
platform_bus_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注册的时候就是挂接到 platform_bus_type->p->klist_devices
下面就是遍历platform_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 = platform_match,最终还是调用到platform的match函数
最终会匹配到 s3c_device_i2c3*/
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
return 0;
/*dev = s3c_device_i2c3->dev
s3c_device_i2c3->dev->parent = &platform_bus */
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/platform/drivers/s3c-i2c创建指向s3c2440-i2c.3的链接,
名字仍然为s3c2440-i2c.3*/
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj));
if (ret == 0) {
/*在sys/bus/platform/device/s3c2440-i2c.3下
创建指向sys/bus/platform/drivers/s3c-i2c的链接,名字为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;
}
/*platform_bus_type->probe = NULL,所以调用
s3c24xx_i2c_driver->probe也就是 s3c24xx_i2c_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);
{ /*前面s3c_device_i2c3->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;
}
/*将s3c24xx_i2c_driver挂接在platform的driver链表中*/
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
/*在/sys/bus/platform/drivers/s3c-i2c创建uevent文件*/
error = driver_create_file(drv, &driver_attr_uevent);
if (error) {
printk(KERN_ERR "%s: uevent attr (%s) failed\n",
__func__, drv->name);
}
/*为 s3c24xx_i2c_driver 创建默认的属性文件,可是platform_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);
}
/*s3c24xx_i2c_driver->drv->suppress_bind_attrs 未赋值,也就是为0*/
if (!drv->suppress_bind_attrs) {
error = add_bind_files(drv);
{
int ret;
/*在/sys/bus/platform/drivers/s3c-i2c目录下创建 ubind 文件*/
ret = driver_create_file(drv, &driver_attr_unbind);
if (ret == 0) {
/*在/sys/bus/platform/drivers/s3c-i2c目录下创建 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;
/*创建属性组及文件,s3c24xx_i2c_driver->drv未初始化,也就是为NULL,不会创建任何文件*/
ret = driver_add_groups(drv, drv->groups);
{
int error = 0;
int i;
if (groups) {
for (i = 0; groups[i]; i++) {
error = sysfs_create_group(&drv->p->kobj, groups[i]);
if (error) {
while (--i >= 0)
sysfs_remove_group(&drv->p->kobj,
groups[i]);
break;
}
}
}
return error;
}
if (ret)
bus_remove_driver(drv);
return ret;
}
}
}
上面的 s3c24xx_i2c_driver 注册过程,大致就是从platform总线上匹配到 s3c_device_i2c3 ,然后调用 s3c24xx_i2c_probe,同时建立一些目录、链接和属性文件。简单一点描述就是先注册个platform类型的device,在注册一个platform类型的driver,在platform总线的牵引(match)下,device 和driver绑定并调用到driver的初始化函数。到此只是驱动模型框架的作用,真正驱动的是从 s3c24xx_i2c_probe 开始,设置时钟,IO口和中断等等。下面看下s3c24xx_i2c_driver 注册过程中产生的文件。
1. 在sys/bus/platform/drivers目录下创建s3c-i2c的目录
[root@FriendlyARM drivers]# ls
alarm s3c-i2c s5p-tmu
......
s3c-i2c s5p-tmu
......
2. 在sys/bus/platform/drivers/s3c-i2c创建指向s3c2440-i2c.3的链接,名字仍然为s3c2440-i2c.3
[root@FriendlyARM s3c-i2c]# cd /sys/bus/platform/drivers/s3c-i2c/
[root@FriendlyARM s3c-i2c]# ls -l
--w------- 1 root root 4096 Jan 1 12:48 bind
lrwxrwxrwx 1 root root 0 Jan 1 12:48 s3c2440-i2c.0 -> ../../../../devices/platform/s3c2440-i2c.0
lrwxrwxrwx 1 root root 0 Jan 1 12:48 s3c2440-i2c.3 -> ../../../../devices/platform/s3c2440-i2c.3
lrwxrwxrwx 1 root root 0 Jan 1 12:48 s3c2440-i2c.4 -> ../../../../devices/platform/s3c2440-i2c.4
s3c2440-i2c.3 -> ../../../../devices/platform/s3c2440-i2c.3
lrwxrwxrwx 1 root root 0 Jan 1 12:48 s3c2440-i2c.4 -> ../../../../devices/platform/s3c2440-i2c.4
3. 在sys/bus/platform/device/s3c2440-i2c.3下创建指向sys/bus/platform/drivers/s3c-i2c的链接,名字为driver
[root@FriendlyARM s3c-i2c]# cd /sys/bus/platform/devices/s3c2440-i2c.3
[root@FriendlyARM s3c2440-i2c.3]# ls -l
lrwxrwxrwx 1 root root 0 Jan 1 13:21 driver -> ../../../bus/platform/drivers/s3c-i2c
drwxr-xr-x 9 root root 0 Jan 1 2016 i2c-3
driver -> ../../../bus/platform/drivers/s3c-i2c
drwxr-xr-x 9 root root 0 Jan 1 2016 i2c-3
4. 在/sys/bus/platform/drivers/s3c-i2c创建uevent文件
[root@FriendlyARM s3c2440-i2c.3]# cd /sys/bus/platform/drivers/s3c-i2c/
[root@FriendlyARM s3c-i2c]# ls
bind s3c2440-i2c.3 s3c2440-i2c.3 s3c2440-i2c.7 unbind
s3c2440-i2c.0 s3c2440-i2c.2 s3c2440-i2c.4 uevent
5.在/sys/bus/platform/drivers/s3c-i2c目录下创建 ubind 文件
在/sys/bus/platform/drivers/s3c-i2c目录下创建 bind 文件
[root@FriendlyARM s3c2440-i2c.3]# cd /sys/bus/platform/drivers/s3c-i2c/
[root@FriendlyARM s3c-i2c]# ls
bind s3c2440-i2c.3 s3c2440-i2c.3 s3c2440-i2c.7 unbind
s3c2440-i2c.0 s3c2440-i2c.2 s3c2440-i2c.4 uevent
bind s3c2440-i2c.3 s3c2440-i2c.3 s3c2440-i2c.7 unbind
s3c2440-i2c.0 s3c2440-i2c.2 s3c2440-i2c.4 uevent
对于uevent、bind和ubind等属性文件,可以查看store和show函数。下面展开一下ubind和bind属性的定义:
static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
展开:
struct driver_attribute driver_attr_unbind =
{
.attr = {
.name = "unbind",
.mode = _mode
},
.show = NULL,
.store = driver_bind,
}
store函数:
static ssize_t driver_unbind(struct device_driver *drv,
const char *buf, size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf);
if (dev && dev->driver == drv) {
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_release_driver(dev);
{
struct device_driver *drv;
drv = dev->driver;
if (drv) {
pm_runtime_get_sync(dev);
driver_sysfs_remove(dev);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBIND_DRIVER,
dev);
pm_runtime_put_sync(dev);
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
drv->remove(dev);
devres_release_all(dev);
dev->driver = NULL;
klist_remove(&dev->p->knode_driver);
if (dev->bus)
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
BUS_NOTIFY_UNBOUND_DRIVER,
dev);
}
}
if (dev->parent)
device_unlock(dev->parent);
err = count;
}
put_device(dev);
bus_put(bus);
return err;
}
从上面代码可看出,像unbind文件中写入device的name,就会取消device和该driver的绑定。
下面再看bind属性的定义:
static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
展开;
struct driver_attribute driver_attr_bind =
{
.attr = {
.name = "bind",
.mode = _mode
},
.show = NULL,
.store = driver_bind,
}
store函数:
static ssize_t driver_bind(struct device_driver *drv,
const char *buf, size_t count)
{
struct bus_type *bus = bus_get(drv->bus);
struct device *dev;
int err = -ENODEV;
dev = bus_find_device_by_name(bus, NULL, buf);
if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
err = 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);
pm_runtime_put_sync(dev);
return ret;
}
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
if (err > 0) {
/* success */
err = count;
} else if (err == 0) {
/* driver didn't accept device */
err = -ENODEV;
}
}
put_device(dev);
bus_put(bus);
return err;
}
从上面的代码可以看出,向bind文件写入device的name,那么就将搜索device和该driver绑定。
上面的unbind和bing是不是很像/sys/bus/platform/下的drivers_probe文件?
下一节将从 s3c24xx_i2c_probe 分析i2c的驱动框架。