Linux Device Driver Learning (12)-Linux Device Model (Basic Principles)

Source: Internet
Author: User
According to ldd3, the Linux device model can be considered as an advanced textbook, which is unnecessary for most program authors. But I personally think: For an embedded Linux underlying programmer, this part of content is very important. For example, I learned about ARM9. many bus (such as SPI, IIC, IIS, and so on) have been written into subsystems in Linux, and no driver needs to be written by myself; unlike PCI, USB, and other tutorials on ldd3, these buses sometimes have to study their own subsystem architecture, or even add a new bus type. For this study, I recommend several web pages. These are the references of my articles: (1) I am sysfs in Linux, which is from the Linux technology blog of Fudan University and Jiaotong University:
URL: Http://blog.csdn.net/fudan_abc(Fudan _ ABC) They also analyzed many Linux drivers, which are worth collecting!
(2) Linux Device Model details is also a blog article by cool people,
Blog website: Http://hi.baidu.com/csdeny/blog
(3) "register the S3C2410 device" is a rare piece of good information about how the Linux kernel implements the device model in 2410.
URL: Http://blog.chinaunix.net/u1/41638/showart_438078.html
(4) luofuchong's blog, who analyzed some Linux subsystems (such as SPI and input) in 2410, is very powerful and worthy of attention.
Web: http://www.cnitblog.com/luofuchong/
In this part of learning, we will first study each element of the Linux device model, and finally integrate it step by step for bottom-up analysis. At the beginning, I was confused, and the integration phase was just a bit confusing. The reason why I didn't first introduce the whole and then analyze each part is that if I didn't make a careful analysis on each element, I would be confused when I saw it ). So at the beginning, we should be able to see what we can do, and we will be very open to the integration stage. The purpose of the Linux device model is to establish a unified device model for the kernel, so as to have a general abstract description of the system structure. Now the kernel uses the device model to support a variety of different tasks:
Power Management and System Shutdown: these require an understanding of the system structure. The device model enables the OS to traverse system hardware in the correct order. Communication with user space: the implementation of the sysfs virtual file system is closely related to the device model and shows the structure it expresses to the outside world. Interfaces that provide system information to user spaces and change operation parameters are increasingly completed through sysfs, that is, device models. Device Type of hot swapping devices: The device model includes a mechanism to classify devices, describe these devices on a higher feature layer, and make devices visible to user space. Object lifecycle: to implement the device model, you need to create a series of mechanisms to process the object lifecycle, relationships between objects, and representation of objects in the user space. The Linux device model is a complex data structure. But for most of the models, the Linux Device Model Code will handle these relationships, rather than imposing them on the driver author. The model is hidden behind the interaction. direct interaction with the device model is usually handled by bus-Level Logic and other kernel subsystems. Therefore, many drivers can ignore the device model and believe that the device model can handle what they are responsible. Before that, let's take a look at sysfs. Let's take a look at those Linux things. I'm talking about sysfs (1) sysfs! We recommend that you first check the sysfs kernel document \ documentation \ filesystems \ sysfs.txt. I will translate it into PDF ,: Http://blogimg.chinaunix.net/blog/upfile2/071229162826.pdf If any error occurs, please correct it! Kobject, kset, and Subsystem KobjectsKobject is a data structure defined in <Linux/kobject. h>.
Struct kobject {const char * k_name;/* kobject name array (name used by sysfs entry) pointer; if the name array is smaller than kobj_name_len, it points to the name of this array, otherwise, point to another allocated name array space */Char name [kobj_name_len];/* kobject name array. If the name array size is not smaller than kobj_name_len, only the first kobj_name_len characters */struct kref;/* Reference count of kobject */struct list_head entry;/* Two-way linked list between kobject, form a circular linked list */struct kobject * parent with the kset;/* locate the object in the sysfs hierarchy and point it to the struct kobject kobj */struct kset * kset in the previous kset; /* point to the kset */struct kobj_type * ktype;/* pointer to the struct kobj_type that tracks the kobject type */struct dentry * dentry; /* file Node path pointer */wait_queue_head_t poll for the object in the sysfs file system;/* waiting queue header */};
Kobject is the basic structure of the device model. It is initially counted as a simple reference, but with the passage of time, its tasks become more and more. Now, kobject processes tasks and supports the following code: object reference count: One way to track object lifecycle is to use reference count. When no kernel code holds a reference to this object, this object ends its effective life cycle and can be deleted. Sysfs representation: each object in sysfs corresponds to a kobject, which interacts with the kernel to create a visible representation of it. Data structure association: In general, the device model is an extremely complex data structure, which forms a multi-level architecture through a large number of links. Kobject implements this structure and aggregates it together. Hot swapping event processing: The kobject subsystem notifies the user space of hot swapping events generated. A kobject is not interested in itself. It has the significance of connecting an advanced object to the device model. Therefore, the kernel code rarely (or even unknown) creates a separate kobject. While kobject is used to control access to objects related to large domains, kobject is embedded into other structures. Kobject can be seen as a top-level base class, and other classes are derived from it. Kobject implements a series of methods that have no special effect on itself, but are very effective on other objects. For a given kobject pointer, you can use the container_of macro to obtain the pointer containing its struct. Kobject InitializationKobject Initialization is complex, but the required steps are as follows: (1) Clear the entire kobject, usually using the memset function. (2) Call the kobject_init () function to set some Members in the structure. One thing you do is to set the reference count of kobject to 1. The specific source code is as follows:
Void kobject_init (struct kobject * kobj)/* In kobject. C */{If (! Kobj) return; kref_init (& kobj-> kref);/* set the reference count to 1 */init_list_head (& kobj-> entry ); /* initialize the two-way linked list between kobject */init_waitqueue_head (& kobj-> poll);/* initialize the waiting queue header */kobj-> kset = kset_get (kobj-> kset ); /* Add the reference count of the kset to which the kset belongs (if no kset belongs, null is returned) */} void kref_init (struct kref * kref)/* In kobject. C */{atomic_set (& kref-> refcount, 1); smp_mb ();} static inline struct kset * to_kset (struct kobject * kobj)/* In kobject. H */{return kobj? Container_of (kobj, struct kset, kobj): NULL;} static inline struct kset * kset_get (struct kset * k)/* In kobject. H */{return K? To_kset (kobject_get (& K-> kobj): NULL;/* Add reference count */}
(3) set the kobject name
int kobject_set_name(struct kobject * kobj, const char * fmt, ...);
(4) directly or indirectly set other members: ktype, kset, and parent. (Important) Operation on reference countAn important function of kobject is to set reference count for the structure containing it. As long as the reference count of this object exists, this object (and the code supporting it) must continue to exist. The underlying functions that control the reference count of kobject include:
Struct kobject * kobject_get (struct kobject * kobj);/* If successful, increment the reference count of kobject and return a pointer to kobject; otherwise, return null. Always test the return value to avoid competing states */void kobject_put (struct kobject * kobj);/* decrease the reference count and release this object whenever possible */
Note: kobject _ init sets this reference count to 1. Therefore, when creating a kobject, when this initialization reference is no longer needed, make sure to call kobject_put. Similarly, the reference count of struct cdev is implemented as follows:
struct kobject *cdev_get(struct cdev *p){struct module *owner = p->owner;struct kobject *kobj;if (owner && !try_module_get(owner))return NULL; kobj = kobject_get(&p->kobj);if (!kobj) module_put(owner);return kobj;}
When creating a reference to the cdev structure, you also need to create a reference to the module that contains it. Therefore, cdev_get uses try_module_get to increase the reference count of this module. If this operation succeeds, kobject_get is also used to increase the reference count of kobject. Kobject_get may fail. Therefore, this code checks the return value of kobject_get. If the call fails, it releases the reference count of the module. Release function and kobject typeReference counting cannot be directly controlled by the Code for creating kobject. When the final reference counting of kobject disappears, it must be notified asynchronously. Then, the release function contained in the kobj_type struct pointed to by ktype in kobject will be called. The typical prototype is as follows:
void my_object_release(struct kobject *kobj){struct my_object *mine = container_of(kobj, struct my_object, kobj);/* Perform any additional cleanup on this object, then... */ kfree(mine);}
Each kobject must have a release function, and the kobject must remain unchanged (stable) before the release function is called ). In this way, each kobject requires an associated kobj_type structure. The pointer to this structure can be found in two different places: (1) the kobject structure itself contains a member (ktype) pointing to kobj_type; (2) If this kobject is a member of a kset, kset provides the kobj_type pointer.
Struct kset {struct kobj_type * ktype;/* pointer to the kset object type */struct list_head list; /* connect all the kobject in the kset to form the linked list header */spinlock_t list_lock;/* to avoid competing spin locks */struct kobject kobj; /* embedded kobject */struct kset_uevent_ops * uevent_ops;/* The original struct kset_hotplug_ops * hotplug_ops; is replaced by the kset_uevent_ops struct and will be introduced in the hot swapping operation */};
The following macro is used to find the kobj_type pointer of a specified kobject: struct kobj_type *get_ktype(struct kobject *kobj);This function returns the kobj_type pointer from the above two points. The source code is as follows:
static inline struct kobj_type * get_ktype(struct kobject * k){if (k->kset && k->kset->ktype)return k->kset->ktype;elsereturn k->ktype;}
Kobj_type of the new kernel version:

In the new kernel version, the struct kobj_type * ktype has been removed from the struct kset; that is, only the struct kobject contains kobj_type, so the get_ktype is changed:
static inline struct kobj_type * get_ktype(struct kobject * kobj){return kobj->ktype;}
Kobject hierarchy, kset, and Subsystem
The kernel usually uses the kobject structure to connect each object to form a layered structure system that matches the modeled subsystem. There are two independent mechanisms for connection: parent pointer and kset. Parent is a pointer to another kobject structure (a node in the upper layer of the hierarchy). It is mainly used to locate objects in the sysfs hierarchy.
KsetKset is like an extension of the kobj_type structure. A kset is a set of kobject embedded into the same type structure. However, struct kobj_type focuses on the object type, while struct kset focuses on Object aggregation and collection. Its main function is tolerance and can be considered as the top-level container class of kobjects. Each kset contains its own kobject, and can be processed in multiple ways. Ksets always appear in sysfs. Once a kset is set and added to the system, a directory is created in sysfs. kobjects does not have to be expressed in sysfs, however, each kobject member in the kset must be expressed in sysfs. Add kobject to kset. It is usually completed when kobject is created. The process is divided into two steps: (1) initialize kobject. Pay special attention to mane, parent, and initialization. (2) point the kset member of kobject to the target kset. (3) pass kobject to the following function:
Int kobject_add (struct kobject * kobj);/* The function may fail (a negative error code is returned), and the program should respond accordingly */
The kernel provides a composite function:
Extern int kobject_register (struct kobject * kobj);/* It is only a combination of kobject_init and kobject_add. Initialization of other Members must be completed manually */
When you delete a kobject from the kset to clear the reference:
Void kobject_unregister (struct kobject * kobj);/* is the combination of kobject_del and kobject_put */
However, no function similar to "register" and "unregister" is available in the new kernel.
extern int __must_check kobject_init_and_add(struct kobject *kobj,struct kobj_type *ktype,struct kobject *parent,const char *fmt, ...);
Therefore, please study this function based on your kernel version. kset stores its child nodes in a standard kernel linked list. In most cases, the included kobjects saves the pointer to the kobject embedded in kset in their parent members, the relationship is as follows: All included kobjects in the chart are actually embedded in some other types, or even other ksets. Operations on ksetKsets have interfaces similar to kobjects initialization and setting:
Void kset_init (struct kset * kset); int kset_add (struct kset * kset); int kset_register (struct kset * kset); void kset_unregister (struct kset * kset ); /* manage ksets reference count: */struct kset * kset_get (struct kset * kset); void kset_put (struct kset * kset);/* kset also has a name, stored in the embedded kobject, so set its name to: */kobject_set_name (& my_set-> kobj, "the name ");
Ksets also has a pointer pointing to the kobj_type structure to describe the kobject it contains. This type prevails over the ktype in the kobject itself. Therefore, in typical applications, the ktype member in struct kobject is set to null, while the ktype in kset is actually used.

In the new kernel, kset no longer contains a sub-system pointer struct subsystem * subsys, And the subsystem has been replaced by kset. SubsystemSubsystem is a description of some advanced components of the entire kernel. Subsystems usually (but not necessarily) appear at the top layer of the sysfs hierarchy. kernel subsystems include block_subsys (/sys/block device) and devices_subsys (/sys/devices core device layer) and specific subsystems known to the kernel for various bus. The new kernel no longer has the subsystem data structure, instead of kset. Each kset must belong to a subsystem. subsystem members help the kernel locate the kset in the hierarchy.
/* Subsystems generally use the following macro Description: */decl_subsys (name, struct kobj_type * type, struct kset_uevent_ops * uevent_ops);/* subsystem operation functions: */void subsystem_init (struct kset * s); int subsystem_register (struct kset * s); void subsystem_unregister (struct kset * s); struct subsystem * subsys_get (struct kset * s) void subsys_put (struct kset * s);/* these functions are basically the packaging of kset operation functions to implement Sub-system operations */

In the new kernel, all the above subsystem functions have been canceled and are completely replaced by kset. The reason may be that the original subsystem function is simply a simple packaging of the kset function, while in the Linux World, simplicity is beautiful, and extra things are removed.

Underlying sysfs operationsKobject is a mechanism after the sysfs Virtual File System. Each directory in sysfs has a corresponding kobject in the kernel. Each kobject outputs one or more attributes. It appears as a file in the sysfs directory of kobject, And the content is generated by the kernel. <Linux/sysfs. h> contains the sysfs working code.

The entry to create a kobject in sysfs is part of the kobject_add job. If you call kobject_add, it will be displayed in sysfs. Some knowledge is worth remembering:

(1) The sysfs entry of kobjects is always a directory. The call of kobject_add will create a directory in sysfs, which contains one or more attributes (files );

(2) the name assigned to kobject (using kobject_set_name) is the directory name in sysfs. The kobjects that appears in the same part of the sysfs hierarchy must have a unique name. the names assigned to kobjects should also be valid file names: they cannot contain illegal characters (such as diagonal lines) and are not recommended to use blank spaces.

(3) The sysfs entry position corresponds to the parent pointer of the kobject. If parent is null, it is set to kobject embedded in the kset of the new kobject. If parent and kset are both null, The sysfs entry directory is at the top level, which is generally not recommended. Default PropertiesWhen a kobject is created, each kobject is given a series of default attributes. These attributes are stored in the kobj_type structure:
Struct kobj_type {void (* release) (struct kobject *); struct sysfs_ops * sysfs_ops;/* provides methods to implement the following attributes */struct attribute ** default_attrs; /* used to save the type attribute list (pointer of the pointer) */}; struct attribute {char * Name;/* attribute name (displayed in the sysfs directory of kobject) */struct module * owner;/* pointer to the module (if any), this module is responsible for implementing this attribute */mode_t mode;/* attribute protection bit, the macro definition of modes is in <Linux/STAT. h>: for example, s_irugo is a read-only attribute */};/* the last element in the default_attrs list must be filled with 0 */
Sysfs reads and writes these attributes by functions in the kobj_type-> sysfs_ops member:
struct sysfs_ops { ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer); ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);};
When a user space reads an attribute, the kernel uses the pointer to kobject (kobj) and the correct attribute structure (* ATTR) to call the show method, this method encodes the given property value into the buffer (note not to cross-border (page_size byte) and returns the actual data length. Sysfs conventions require that each attribute should contain a single human readable value; if a large amount of information is returned, it should be divided into multiple attributes. you can also use the same show method for all attributes associated with kobject, and use the ATTR pointer passed to the function to determine the Requested attribute. Some show methods include checking the attribute name. Some show Methods embed the attribute structure into another structure, which contains information about the attribute values to be returned. In this case, container_of can be used to obtain the pointer of the Upper-layer structure to return the attribute value information. The store method decodes cached data (the size is the length of the data and cannot exceed page_size), saves the new value to the attribute (* ATTR), and returns the actual number of decoded bytes. The store method can be called only when the write permission of an attribute is available. Note: to receive data from a user space, verify its validity. If the data does not match, a negative error value is returned. Non-default attributeAlthough the default_attrs Member of the kobject type describes all attributes that kobject will possess, if you want to add a new attribute to the sysfs Directory attribute of kobject, you only need to simply fill in an attribute structure and pass it to the following functions:
Int sysfs_create_file (struct kobject * kobj, struct attribute * ATTR);/* If successful, the file is created with the name in the attribute structure and 0 is returned; otherwise, return negative error code * // * Note: The kernel calls the same show () and store () functions to perform operations on new attributes. Therefore, before adding a new non-default attribute, necessary steps should be taken to ensure that these functions know how to implement this attribute */
To delete a property, call:
Int sysfs_remove_file (struct kobject * kobj, struct attribute * ATTR);/* after calling, this attribute no longer appears at the sysfs entry of kobject. If a user space process may have a file descriptor of the opened attribute, after the attribute is deleted, show and store may still be called */
Binary AttributeSysfs usually requires that all attributes contain only one value in the readable text format, and seldom needs to create attributes that can process a large amount of binary data. This feature is required when unchangeable data is transmitted between the user space and the device (for example, the firmware is uploaded to the device. The binary attribute is described using a bin_attribute structure:
Struct bin_attribute {struct attribute ATTR;/* attribute struct */size_t size;/* maximum size of the Binary Attribute (0 if no maximum value exists) */void * private; ssize_t (* read) (struct kobject *, char *, loff_t, size_t); ssize_t (* write) (struct kobject *, char *, loff_t, size_t ); /* The read and write methods are similar to the character-driven read and write methods. The read and write methods can be called multiple times during a single load, and the maximum number of data pages can be operated at a time, you must be able to determine the end */INT (* MMAP) (struct kobject *, struct bin_attribute * ATTR, struct vm_area_struct * VMA) of the operation data in other ways );}; /* the Binary Attribute must be explicitly created and cannot be created with the default attribute. Create a Binary Attribute called: */INT sysfs_create_bin_file (struct kobject * kobj, struct bin_attribute * ATTR ); /* Call to delete binary attributes: */INT sysfs_remove_bin_file (struct kobject * kobj, struct bin_attribute * ATTR );
Symbolic LinkThe sysfs file system has a tree structure that reflects the organizational hierarchy between kobject. To represent the relationship between the driver and the managed device, additional pointers are required, which are implemented through symbolic links in sysfs.
/* Create a symbolic link in sysfs: */INT sysfs_create_link (struct kobject * kobj, struct kobject * target, char * Name);/* create a link (name) for the function) the sysfs entry pointing to the target is a property of kobj, which is a relative connection and has nothing to do with its position in the sysfs system. * // * Delete the symbolic connection call: */void sysfs_remove_link (struct kobject * kobj, char * Name );
Hot swapping event generationA hot swapping event is a notification sent from the kernel space to the user space, indicating that the system configuration has changed. This event is generated no matter whether the kobject is created or deleted. Hot swapping events can cause/sbin/hotplug calls, which respond to events by loading drivers, creating device nodes, attaching partitions, or other correct actions.

The actual control of hot swapping events is implemented through a set of methods stored in the structure of kset_uevent_ops (struct kset_hotplug_ops * hotplug_ops introduced in ldd3; it has been replaced by the kset_uevent_ops struct in 2.6.22.2:
struct kset_uevent_ops {int (*filter)(struct kset *kset, struct kobject *kobj);const char *(*name)(struct kset *kset, struct kobject *kobj);int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,int num_envp, char *buffer, int buffer_size);};
You can find the pointer to the kset_uevent_ops structure in the uevent_ops Member of the kset structure. If the specified kset is not included in the kobject, the kernel searches in the layered structure through the parent pointer until a kobject containing the kset is found. Then, the kset hot swapping operation is used. The three methods in the kset_uevent_ops structure have the following functions:

(1) The filter function allows the kset code to determine whether to pass the event to the user space. If the filter returns 0, no event is generated. Taking the disk filter function as an example, it only allows kobject to generate disk and partition events. The source code is as follows:
static int block_hotplug_filter(struct kset *kset, struct kobject *kobj){struct kobj_type *ktype = get_ktype(kobj);return ((ktype == &ktype_block) || (ktype == &ktype_part));}
(2) When a user space hot swapping program is called, the sub-system name will be passed to it as a unique parameter. The name function is responsible for returning suitable strings to the hot swapping program in the user space. (3) Any other parameters obtained by the hot swapping script are passed through environment variables. The uevent function adds parameters to environment variables before calling the hot swapping script. Function prototype:
INT (* uevent) (struct kset * kset, struct kobject * kobj,/* target object for event generation */Char ** envp, /* an array that stores definitions of other environment variables (usually in name = value format) */INT num_envp,/* number of variables contained in the environment variable array (array size) */char * buffer, int buffer_size/* pointer and number of characters (size) of the buffer into which the environment variables are encoded * // * if you need to add any environment variables to envp, you must add a null entry after the last entry to let the kernel know the end of the array */);/* the return value should be 0, if a non-zero value is returned, the hot swapping event will be terminated */
Hot swapping events are usually generated by the logic at the bus driver layer. The above is an overview of the underlying principles of the Linux device model. For details, refer to the kernel source code and ulk3.

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.