The influence and relationship of successive registration of device device register and driver driver register under linux

This article is a summary of reading the source code by myself. Please indicate the source of the transfer. Thank you.

Welcome to communicate with you. qq:1037701636 email: 200803090209@zjut.com , gzzaigcn2012@gmail.com

Before I start my blog post, I just want to talk about the feeling of the last day. In the Linux world, playing on the surface is easy, but playing on the inside is courting death. Admire those who write the [source code] . Really admire.

This world has been around for about half a month, and the real development of linux drivers started from the grassroots level. Compared with Leds that think that the driver under linux is like lighting, now my feeling is that those are completely superficial things. The driver at the core level is not written so casually at all. It also just shows that many companies are writing not many drivers, and not many completely independent writing, because it is too complicated. Only rely on source code or BSP to modify. I have seen the audio driver OSS architecture under linux 2.6.10 for more than half a month, and it is not complicated. Familiar with the entire architecture of the I2C driver (I wrote a blog post before).

Why write this content again today, because I recently started watching the video architecture under linux. I saw device_register and driver_register in a trance. These two things are the real core of the driver, which made me realize who needs to be executed first, or it doesn’t matter. Baidu has read a lot, and they are all talking about superficial articles. Going to QQ is also full of ashes, so I still solve it independently, although I know that basically no one thinks about this problem (except for the gods who wrote the kernel), because this piece of content and The kernel is very close, and the amount of code is large. So the basic visible analysis is on the surface. Therefore, I write my analysis and summary here for everyone to learn from, and please correct me if I am wrong.

Judging from the source code of the functions driver_register and device_register, the execution order of these two functions appears before and after, but they were all on the surface before, and I haven’t seen it in depth, because it is very complicated to know that the kernel is going deeper. But in order to solve the problem will only bite the bullet and watch. The following is some of my analysis, mainly related to the linked list, kobject, kset, bus, device, device_driver several structures.

  1. Start with the calling process of driver_register, mainly introduce the core calling, and some functions in between are not parsed.

driver_register->bus_add_driver->

int bus_add_driver(struct device_driver * drv)
{
    struct bus_type * bus = get_bus(drv->bus);
    int error = 0;

    if (bus) {
        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
        error = kobject_set_name(&drv->kobj, "%s" , drv->name);   //Give a name to kobj 
        if (error) {
            put_bus(bus);
            return error;
        }
        drv->kobj.kset = &bus->drivers;   //kset points to bus->drivers (type is kset) 
        if ((error = kobject_register(&drv->kobj))) {
            put_bus(bus);
            return error;
        }

        down_read(&bus->subsys.rwsem);
        driver_attach(drv);
        up_read(&bus->subsys.rwsem);
        module_add_driver(drv->owner, drv);

        driver_add_attrs(bus, drv);
    }
    return error;
}

In this function, I think the core is the statement drv->kobj.kset = &bus->drivers;, why do you say this. Because in fact, during the registration process of the device and the driver, the linked list members of their own structures will be added to the linked list with bus->drivers and bus->devices as the linked list header. Finally, it traverses the addresses of the members according to these linked lists, and then finds out whether the device and the driver execute the probe in turn.

So drv->kobj.kset = &bus->drivers; this needs to be combined with the function kobject_register->kobject_add function

static void unlink(struct kobject * kobj)
{
    if (kobj->kset) {
        down_write(&kobj->kset->subsys->rwsem);
        list_del_init(&kobj->entry);
        up_write(&kobj->kset->subsys->rwsem);
    }
    kobject_put(kobj);
}

/**
 *  kobject_add - add an object to the hierarchy.
 *  @kobj:  object.
 */

int kobject_add(struct kobject * kobj)
{
    int error = 0;
    struct kobject * parent;

    if (!(kobj = kobject_get(kobj)))
        return -ENOENT;
    if (!kobj->k_name)
        kobj->k_name = kobj->name;
    parent = kobject_get(kobj->parent);

    pr_debug("kobject %s: registering. parent: %s, set: %s\n",
         kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", 
         kobj->kset ? kobj->kset->kobj.name : "<NULL>" );

    if (kobj->kset) {
        down_write(&kobj->kset->subsys->rwsem);

        if (!parent)
            parent = kobject_get(&kobj->kset->kobj);

        list_add_tail(&kobj->entry,&kobj->kset->list);   //The list_head content of kobj is added to the list list of bus->drivers
        up_write(&kobj->kset->subsys->rwsem);
    }
    kobj->parent = parent;

    error = create_dir(kobj);
    if (error) {
        /* unlink does the kobject_put() for us */
        unlink(kobj);
        if (parent)
            kobject_put(parent);
    } else {
        kobject_hotplug(kobj, KOBJ_ADD);
    }

    return error;
}

Here is such a list_add_tail macro to complete the device_driver adding the kset list header of the member kobject to kobj->kset->list, which is actually drv->kobj.kset = &bus->drivers, that is, adding to the list header Go to bus->drivers->list. In this way, when the device is registered, it can traverse to the driver under the head of the linked list.

To sum up, in fact, devices and drivers will eventually be attached to the bus during registration, and the type is the list under kset (device and driver). In the end, they all traverse the corresponding drivers and devices under the head of the linked list. And we know that a driver can have multiple devices, so the driver_list under the device will be added to the list header under the driver.

Compared with the implementation of driver_register, the implementation of device_register is much simpler, a sentence list_add_tail(&dev->bus_list, &dev->bus->devices.list); //Add the bus_list of the device to the linked list header of devoces.list , this is much, much simpler. It is clear that there is no need to add the linked list under kobj to the Bus for traversal like the driver.

In short, this problem is very small, but it is very close to the kernel, so I think I must solve this problem, which can give me a deep understanding of the driver. Keep working hard and walk in the world of linux

Leave a Comment

Your email address will not be published. Required fields are marked *