Linux Kernel Lecture Hall (1) cornerstone Driver Model for device drivers (1)

Source: Internet
Author: User

It may be difficult to put the driver model in the first chapter, but as long as the driver model can be crossed, it will be much easier later. The driver model is the cornerstone of the entire Linux Device Driver. Most people call the driver model a device model, but I have checked the help document of Linux to find the driver-model directory in the documentation directory under the download source code path, the files contained in this section are what I will talk about in this chapter, that is, what I call the driver model. Therefore, this article will use the term "Driver Model" (if you think this method is incorrect, please comment it out in the comments and give reasons, I sincerely accept your criticism and corrections ). The core structure of the driver model is what we call bus, device, and device_driver. Bus, device, and device driver. First, we need to analyze the Linux kernel to have a hierarchical concept. Linux is designed to be a layer-by-layer concept. Under this layer, there is also a layer composed of kobject, kobj_type, and kset, we can also consider it to be within the scope of the driver model. We can see that the kernel describes it as: Generic kernel object infrastructure. Is the basic meaning of General kernel objects. Let's call it the Kernel Object layer for the moment. At the upper layer of the driver model, we can encapsulate sub-systems of each sub-module. This will be explained later.
First, let's take a look at what the Kernel Object layer is and what features it has. Please be patient during the analysis process. In this case, you only need patience.
First, the prototype of each member in the Kernel Object layer is given:
Struct kobject {
Const char * Name;
Struct list_head entry;
Struct kobject * parent;
Struct kset * kset;
Struct kobj_type * ktype;
Struct sysfs_dirent * SD;
Struct kref;
Unsigned int state_initialized: 1;
Unsigned int state_in_sysfs: 1;
Unsigned int state_add_uevent_sent: 1;
Unsigned int state_remove_uevent_sent: 1;
Unsigned int uevent_suppress: 1;
};

Struct kset {
Struct list_head list;
Spinlock_t list_lock;
Struct kobject kobj;
Struct kset_uevent_ops * uevent_ops;
};

Struct kobj_type {
Void (* release) (struct kobject * kobj );
Struct sysfs_ops * sysfs_ops;
Struct attribute ** default_attrs;
};
First, from the members of each struct, we find that there is no triangle relationship between them. kobject contains kobj_type and kset and itself. kset contains kobject, while kobj_type does not include the above two, as long as it is a brother on the road, we can see that kobject occupies an absolute position in this relationship.
The Linux Kernel provides methods for operating these three elements. (In kobject. C ).
Let's talk about the following:
Void kobject_init (struct kobject * kobj, struct kobj_type * ktype)
{
Char * err_str;

If (! Kobj ){
Err_str = "invalid kobject pointer! ";
Goto error;
}
If (! Ktype ){
Err_str = "must have a ktype to be initialized properly! /N ";
Goto error;
}
If (kobj-> state_initialized ){
/* Do not error out as sometimes we can recover */
Printk (kern_err "kobject (% P): tried to init an initialized"
"Object, something is seriously wrong./N", kobj );
Dump_stack ();
}

Kobject_init_internal (kobj );
Kobj-> ktype = ktype;
Return;

Error:
Printk (kern_err "kobject (% P): % s/n", kobj, err_str );
Dump_stack ();
}

Let's take a look at it. (the initialization and legal condition judgment are very important in actual operation, but for our analysis, as long as we can grasp the main line, analyze the content we are interested in.) You can simplify this function:
Void kobject_init (struct kobject * kobj, struct kobj_type * ktype)
{
Char * err_str;
Kobject_init_internal (kobj );
Kobj-> ktype = ktype;
Return;
}
OK. We can see that two parameters are passed in. One is the pointer of kobject and the other is the pointer of kobj_type. After calling kobject_init_internal (kobj, assign the passed ktype to the ktype Member of the kobject. Let's take a look at how ktype exists. Before analyzing the ktype, we need to first run a layer. For this layer, we select the int device_register (struct device * Dev) function, and first give the function prototype:
Int device_register (struct device * Dev)
{
Device_initialize (Dev );
Return device_add (Dev );
}
Void device_initialize (struct device * Dev)
{
Dev-> kobj. kset = devices_kset;
Kobject_init (& Dev-> kobj, & device_ktype );
Init_list_head (& Dev-> dma_pools );
Init_mutex (& Dev-> SEM );
Spin_lock_init (& Dev-> devres_lock );
Init_list_head (& Dev-> devres_head );
Device_init_wakeup (Dev, 0 );
Device_pm_init (Dev );
Set_dev_node (Dev,-1 );
}
Find the kobject_init (& Dev-> kobj, & device_ktype) that we are interested in );
Let's see the definition of device_ktype:
Static struct kobj_type device_ktype = {
. Release = device_release,
. Sysfs_ops = & dev_sysfs_ops,
};
Obviously, the role of release is release. As for how to release, we will not look at it first. The following is sysfs_ops. This sysfs interface communicates with the user space. Let's click to view it:
Static struct sysfs_ops dev_sysfs_ops = {
. Show = dev_attr_show,
. Store = dev_attr_store,
}; Corresponds to the two actions we read and write to the nodes under sysfs respectively. We don't care what it is. From the above, we know that ktype contains a sysfs read/write interface and a function with the release function.
Back to our previous content: the simplified kobject_init function:
Void kobject_init (struct kobject * kobj, struct kobj_type * ktype)
{
Char * err_str;
Kobject_init_internal (kobj );
Kobj-> ktype = ktype;
Return;
}
The rest is kobject_init_internal (kobj.
Static void kobject_init_internal (struct kobject * kobj)
{
If (! Kobj)
Return;
Kref_init (& kobj-> kref );
Init_list_head (& kobj-> entry );
Kobj-> state_in_sysfs = 0;
Kobj-> state_add_uevent_sent = 0;
Kobj-> state_remove_uevent_sent = 0;
Kobj-> state_initialized = 1;
}
The function is purely initialized.
From this initial experience, we learned something updated:
Kref_init (& kobj-> kref );
This is called reference counting. The function of kref_init is to set kobjct-> kref to 1.
The next step is to initialize the kobject-> entry linked list (the Linux kernel linked list is very important and exquisite, and there are many good articles related to the Internet, please read and learn by yourself ).
The next step is a bunch of bit domains.
The member kobj-> state_in_sysfs is named as follows: Indicates whether sysfs is used. The initialization value is 0, which is obviously not used yet.
The names of kobj-> state_add_uevent_sent and kobj-> state_remove_uevent_sent are also intuitive: Specify whether an event is loaded or deleted. This is related to hot swapping. When we add a device or delete a device, the domain is set to 1 when appropriate.
Kobj-> state_initialized indicates whether kobject has been initialized, which is the only one with 1. Obviously, it is initialized.
Before the analysis, it is necessary to explain that, in order to make our analysis more concise, we will only analyze the relevant members of the structure when appropriate, it will not describe all the roles of members in the case of no use.
Int device_add (struct device * 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 shoshould all be converted
* Some day, we need to initialize the name. We prevent reading back
* The name, and force the use of dev_name ()
*/
If (Dev-> init_name ){
Dev_set_name (Dev, "% s", Dev-> init_name );
Dev-> init_name = NULL;
}

If (! Dev_name (Dev ))
Goto name_error;

Pr_debug ("device: '% s': % s/n", dev_name (Dev), _ FUNC __);

Parent = get_device (Dev-> parent );
Setup_parent (Dev, parent );

/* 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 */
Error = kobject_add (& Dev-> kobj, Dev-> kobj. Parent, null );
If (error)
Goto error;

/* Policy platform of device entry */
If (platform_policy)
Platform_policy (Dev );

Error = device_create_file (Dev, & uevent_attr );
If (error)
Goto attrerror;

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 );
If (error)
Goto symlinkerror;
Error = device_add_attrs (Dev );
If (error)
Goto attrserror;
Error = bus_add_device (Dev );
If (error)
Goto buserror;
Error = dpm_sysfs_add (Dev );
If (error)
Goto dpmerror;
Device_pm_add (Dev );

/* Sort y 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_policy_add_device, Dev );

Kobject_uevent (& Dev-> kobj, kobj_add );
Bus_probe_device (Dev );
If (parent)
Klist_add_tail (& Dev-> P-> knode_parent,
& Parent-> P-> klist_children );

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-> class_devices );

/* Define y 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 ))
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;
}
When you see this paragraph, do you feel very depressed? I am also very depressed, but my brother is very happy to say: According to our current functions, we only analyze kobject_add (& Dev-> kobj, Dev-> kobj. parent, null) is enough. In fact, it is very easy to find confidence from the low point of life, just now. First, define the function:
Int kobject_add (struct kobject * kobj, struct kobject * parent,
Const char * FMT ,...)
{
Va_list ARGs;
Int retval;

If (! Kobj)
Return-einval;

If (! Kobj-> state_initialized ){
Printk (kern_err "kobject '% s' (% P): tried to add"
"Uninitialized object, something is seriously wrong./N ",
Kobject_name (kobj), kobj );
Dump_stack ();
Return-einval;
}
Va_start (ARGs, FMT );
Retval = kobject_add_varg (kobj, parent, FMT, argS );
Va_end (ARGs );

Return retval;
}
The code is much less.
We can see that the core function is kobject_add_varg (kobj, parent, FMT, argS), which is defined as follows:
Static int kobject_add_varg (struct kobject * kobj, struct kobject * parent,
Const char * FMT, va_list vargs)
{
Int retval;

Retval = kobject_set_name_vargs (kobj, FMT, vargs );
If (retval ){
Printk (kern_err "kobject: can not set name properly! /N ");
Return retval;
}
Kobj-> parent = parent;
Return kobject_add_internal (kobj );
}
The kobject_set_name_vargs is used to set the kobject name.
Int kobject_set_name_vargs (struct kobject * kobj, const char * FMT,
Va_list vargs)
{
Const char * old_name = kobj-> name;
Char * s;

If (kobj-> name &&! FMt)
Return 0;

Kobj-> name = kvasprintf (gfp_kernel, FMT, vargs );
If (! Kobj-> name)
Return-enomem;

/* Ewww... some of these buggers have '/' in the name ...*/
While (S = strchr (kobj-> name ,'/')))
S [0] = '! ';

Kfree (old_name );
Return 0;
}
The following is the kobject_add_internal function, which is defined as follows:
Static int kobject_add_internal (struct kobject * kobj)
{
Int error = 0;
Struct kobject * parent;

If (! Kobj)
Return-enoent;

If (! Kobj-> name |! Kobj-> name [0]) {
Warn (1, "kobject: (% P): attempted to be registered with empty"
"Name! /N ", kobj );
Return-einval;
}

Parent = kobject_get (kobj-> parent );

/* Join kset if set, use it as parent if we do not already have one */
If (kobj-> kset ){
If (! Parent)
Parent = kobject_get (& kobj-> kset-> kobj );
Kobj_kset_join (kobj );
Kobj-> parent = parent;
}

Pr_debug ("kobject: '% s' (% P): % s: parent:' % s', set: '% s'/N ",
Kobject_name (kobj), kobj, _ FUNC __,
Parent? Kobject_name (parent): "<null> ",
Kobj-> kset? Kobject_name (& kobj-> kset-> kobj): "<null> ");

Error = create_dir (kobj );
If (error ){
Kobj_kset_leave (kobj );
Kobject_put (parent );
Kobj-> parent = NULL;

/* Be noisy on error issues */
If (error =-eexist)
Printk (kern_err "% s failed for % s"
"-Eexist, don't try to register things"
"The same name in the same directory./N ",
_ FUNC __, kobject_name (kobj ));
Else
Printk (kern_err "% s failed for % s (% d)/n ",
_ FUNC __, kobject_name (kobj), error );
Dump_stack ();
} Else
Kobj-> state_in_sysfs = 1;

Return Error;
}
With the intuition of a programmer, we can see that the most important thing is create_dir (kobj). That's right, brother guessed it. It is related to sysfs and creates a directory, this function is widely involved and we will not analyze it for the moment. Revenge for a gentleman. It's not too late for ten years. Let's see who laughed at the end. After create_dir (kobj), set kobj-> state_in_sysfs = to 1. It is nice to hit the old acquaintance. We will hit more and more old acquaintances in the subsequent analysis of the kernel and get to know more new friends. Even the famous singer Yin xiomei knows how to learn the kernel: meet new friends and never forget old friends ...... (Friends should have known each other after the 80 s, and those who are later than the 90 s may not have known each other ).
Next we will analyze a function related to kset, that is, the function prototype is given first:
Struct kset * kset_create_and_add (const char * Name,
Struct kset_uevent_ops * uevent_ops,
Struct kobject * parent_kobj)
{
Struct kset * kset;
Int error;

Kset = kset_create (name, uevent_ops, parent_kobj );
If (! Kset)
Return NULL;
Error = kset_register (kset );
If (error ){
Kfree (kset );
Return NULL;
}
Return kset;
}
Similar to the analysis of kobject in the previous section, to better illustrate this function, we must first jump to the previous layer. It is necessary to see which of the following friends have called it: int bus_register (struct bus_type * Bus ). Well-known bus registration.
We can see several lines of code in the bus_register function:

Priv-> devices_kset = kset_create_and_add ("devices", null,
& Priv-> subsys. kobj );
If (! Priv-> devices_kset ){
Retval =-enomem;
Goto bus_devices_fail;
}

Priv-> drivers_kset = kset_create_and_add ("drivers", null,
& Priv-> subsys. kobj );
The relationship between kset and bus is obvious. OK. Based on the first section, we introduced a regular string "devices", a null pointer, and a kobject pointer.
The function is called first.
Static struct kset * kset_create (const char * Name,
Struct kset_uevent_ops * uevent_ops,
Struct kobject * parent_kobj)
{
Struct kset * kset;
Int retval;

Kset = kzarloc (sizeof (* kset), gfp_kernel); // assign a kset struct and initialize it.
If (! Kset)
Return NULL;
Retval = kobject_set_name (& kset-> kobj, name); // assign the input constant string to // kset-> kobj-> name
If (retval ){
Kfree (kset );
Return NULL;
}
Kset-> uevent_ops = uevent_ops; // set uevent_ops
Kset-> kobj. Parent = parent_kobj; // assign the parent class kobject pointer to kset-> kobj. Parent

/*
* The kobject of this kset will have a type of kset_ktype and belong
* No kset itself. That way we can properly free it when it is
* Finished being used.
*/
Kset-> kobj. ktype = & kset_ktype; // assign kset_ktyp to kset-> kobj. Parent
Kset-> kobj. kset = NULL; // assign null to kset-> kobj. kset

Return kset;
}
From the red comment above, we can see the importance of the built-in kobject in kset. This is an important relationship between kset and kobject. There is one sentence to describe "you" and "you. Next we will pass the completed kset pointer to kset_register.
Int kset_register (struct kset * K)
{
Int err;

If (! K)
Return-einval;

Kset_init (k );
Err = kobject_add_internal (& K-> kobj );
If (ERR)
Return err;
Kobject_uevent (& K-> kobj, kobj_add );
Return 0;
}

Void kset_init (struct kset * K)
{
Kobject_init_internal (& K-> kobj );
Init_list_head (& K-> list );
Spin_lock_init (& K-> list_lock );
}
The next step is kobject_add_internal (& K-> kobj), and it hits the old acquaintance again. Let's sing again: meet new friends, never forget old friends...
Now, we know the relationship between kobject, kobj_type, and kset. The following figure shows the relationship between the three:

 

 


Well, smoke the cigarette first. We will continue to analyze it in the next section.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.