图1-11是注册一个pci设备以后sysfs的目录结构.
首先来看看devices目录是怎么建立起来的.
devices初始化
1072 int __init devices_init(void)
1073 {
1074 devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
1075 if (!devices_kset)
1076 return -ENOMEM;
1077 return 0;
1078 }
这个函数就是注册一个devices_kset 如图1-11会建立一个devices目录.
devices注册
如果向内核注册一个设备就会在devices目录下或者在class目录下建立一个目录.
在讨论注册流程之前,先来看看struct device的定义:
struct device {
struct klist klist_children;
struct klist_node knode_parent;
struct klist_node knode_driver;
struct klist_node knode_bus;
struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE];
struct device_type *type;
unsigned uevent_suppress:1;
struct semaphore sem;
struct bus_type *bus;
struct device_driver *driver;
void *driver_data;
void *platform_data;
struct dev_pm_info power;
#ifdef CONFIG_NUMA
int numa_node;
#endif
u64 *dma_mask;
u64 coherent_dma_mask;
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem;
struct dev_archdata archdata;
spinlock_t devres_lock;
struct list_head devres_head;
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
struct device结构包含了一个kobject结构, 所以我们可以猜想一下,注册一个device其实就是向内核注册一个kobj. 先来理理设备注册的流程:
device_register()->device_initialize()->device_add()->setup_parent()->kobject_add()->device_create_file()->device_add_attrs()->bus_add_device()->kobject_uevent()->bus_attach_device()
调用函数device_register()向内核注册一个设备,传入的参数是struct device *dev, 这个dev往往是被包含在另一个更大的结构中的, 一般不单独使用了.
注册之前先是初始化device结构, device_initialize()这个函数设置了dev包含kobj的.kset 和ktype,( dev->kobj.kset = devices_kset;kobject_init(&dev->kobj, &device_ktype))
好了下面看下注册设备的核心函数dev_add():
789 int device_add(struct device *dev)
790 {
791 struct device *parent = NULL;
792 struct class_interface *class_intf;
793 int error;
794
795 dev = get_device(dev);
796 if (!dev || !strlen(dev->bus_id)) {
797 error = -EINVAL;
798 goto Done;
799 }
800
801 pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
802
803 parent = get_device(dev->parent);
804 setup_parent(dev, parent);
805
806 /* use parent numa_node */
807 if (parent)
808 set_dev_node(dev, dev_to_node(parent));
809
810 /* first, register with generic layer. */
811 error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
812 if (error)
813 goto Error;
814
815 /* notify platform of device entry */
816 if (platform_notify)
817 platform_notify(dev);
818
819 /* notify clients of device entry (new way) */
820 if (dev->bus)
821 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
822 BUS_NOTIFY_ADD_DEVICE, dev);
823
824 error = device_create_file(dev, &uevent_attr);
825 if (error)
826 goto attrError;
827
828 if (MAJOR(dev->devt)) {
829 error = device_create_file(dev, &devt_attr);
830 if (error)
831 goto ueventattrError;
832 }
833
834 error = device_add_class_symlinks(dev);
835 if (error)
836 goto SymlinkError;
837 error = device_add_attrs(dev);
838 if (error)
839 goto AttrsError;
840 error = bus_add_device(dev);
841 if (error)
842 goto BusError;
843 error = device_pm_add(dev);
844 if (error)
845 goto PMError;
846 kobject_uevent(&dev->kobj, KOBJ_ADD);
847 bus_attach_device(dev);
848 if (parent)
849 klist_add_tail(&dev->knode_parent, &parent->klist_children);
850
851 if (dev->class) {
852 down(&dev->class->sem);
853 /* tie the class to the device */
854 list_add_tail(&dev->node, &dev->class->devices);
855
856 /* notify any interfaces that the device is here */
857 list_for_each_entry(class_intf, &dev->class->interfaces, node)
858 if (class_intf->add_dev)
859 class_intf->add_dev(dev, class_intf);
860 up(&dev->class->sem);
861 }
862 Done:
……………..
}
第795行,增加dev->kobj引用计数.
第803行,取出dev的父对象, 并增加其引用计数/
第804行, 安装dev->kobj的父对象,看看这段代码:
static void setup_parent(struct device *dev, struct device *parent)
{
struct kobject *kobj;
kobj = get_device_parent(dev, parent);
if (kobj)
dev->kobj.parent = kobj;
}
如果定义了dev->class将会取出dev->class->subsys.kobj对象作为dev->kobj的父对象 ,否则把parent->kobj对象作为dev->kobj的父对象.
第811行, 注册一个kobject, 这个函数在以前已经分析过了,这里就不看了. 这时设备目录就建立起来了.
下面的代码就是需要建立一些设备属性文件了.
第824行,在刚建立起来的设备目录下创建一个uevent设备属性文件.
第828-829行, 如果定义了设备号dev->devt, 就会创建一个名叫dev的设备属性文件 ,我们可以通过这个文件查看设备号.
第840行代码, 在dev关联的总线(bus/device)目录下创建符号链接文件,
第846行, 向udev发送一个KOBJ_ADD事件的消息.
第847行代码, bus_attach_device(dev) 与注册在总线上的驱动进行匹配 .我们来详细分析一下这个函数:
匹配设备驱动
匹配总线上驱动的软件流程如下:
bus_attach_device()->device_attach()->__device_attach()->driver_probe_device()->really_probe()->driver_bound
首先看看device_attach()代码:
int device_attach(struct device *dev)
{
int ret = 0;
down(&dev->sem);
if (dev->driver) { //如果设备以定义了驱动
ret = device_bind_driver(dev); //绑定驱动
if (ret == 0)
ret = 1;
else {
dev->driver = NULL;
ret = 0;
}
} else {
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //遍历总线上的驱动并与设备匹配
}
up(&dev->sem);
return ret;
}
首先要判断设备是否已经指定了驱动,如果已经指定了驱动就只需要绑定驱动就可以了, 否则就需要遍历总线上的驱动然后进行匹配.
来看看绑定驱动都做了些什么操作:
device_bind_driver()->driver_sysfs_add()
static int driver_sysfs_add(struct device *dev)
{
int ret;
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
kobject_name(&dev->kobj)); //在bus/driver目录下创建一个名字为设备名的符号链接
if (ret == 0) {
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
"driver"); //在device目录下创建一个名字为driver的符号链接文件
if (ret)
sysfs_remove_link(&dev->driver->p->kobj,
kobject_name(&dev->kobj));
}
return ret;
}
好了指定驱动的情况分析完了,,下面接着分析设备没有指定驱动的情况 .
下面看看bus_for_each_drv()代码片段:
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,
void *data, int (*fn)(struct device_driver *, void *))
{
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);
klist_iter_exit(&i);
return error;
}
这个函数就是遍历bus->p->klist_drivers下面挂的驱动,然后调用一个回调函数fn(drv, data)进行匹配工作.
在这里这个回调函数就是__device_attach() ,这个函数会调用函数driver_probe_device();来跟踪一下它:
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
int ret = 0;
if (!device_is_registered(dev)) //如果设备已经注册,返回错误
return -ENODEV;
if (drv->bus->match && !drv->bus->match(dev, drv)) //调用总线定义的match方法进行匹配
goto done;
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev->bus_id, drv->name);
ret = really_probe(dev, drv);
done:
return ret;
}
如果总线定义了match匹配方法的话,就要调用这个回调函数进行初级匹配.
接下来做进一步匹配工作,由really_probe()函数实现:
static int really_probe(struct device *dev, struct device_driver *drv)
{
int ret = 0;
………………
dev->driver = drv;
if (driver_sysfs_add(dev)) { //建立相关符号链接文件,,前面以分析过.
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__func__, dev->bus_id);
goto probe_failed;
}
if (dev->bus->probe) { //首先调用总线定义的prob回调函数
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) { //然后调用驱动定义的prob回调函数
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
driver_bound(dev); //绑定设备和驱动
ret = 1;
pr_debug("bus: '%s': %s: bound device %s to driver %s\n",
drv->bus->name, __func__, dev->bus_id, drv->name);
goto done;
…………….
}
这个函数中有两个重要的回调函数 dev->bus->probe(dev)和drv->probe(dev); 在以后研究具体设备驱动时会看到它的用处. 设备驱动的匹配就分析完了.
好了,在内核注册一个设备的流程就是这样子了.