Misc subsystem and linuxmisc subsystem in linux
Misc Subsystem
Reprinted please indicate the source: http://blog.csdn.net/wang_zheng_kai
Optical source device and System Research Institute
Personal Learning Summary
1. What is misc in linux?
When studying the camera driver, we found that the camera driver path is in the/driver/misc/jz_cim/file directory. The search results are as follows:
Miscellaneous device (misc device)
Miscellaneous devices are also a device driver used in many embedded systems. There is a miscdevice. h file in the include/Linux directory of the linux kernel. You need to define your own misc device from the device here. The reason is that these character devices do not conform to the predefined category of character devices. All these devices use the No. 10, which is attributed to misc device. In fact, misc_register calls register_chrdev () with the primary number 10, however, misc stores some character devices in the misc class. In other words, the misc device is actually a special character device.
2. Linux kernel miscellaneous device driver source code analysis
In Linux drivers, devices that cannot be categorized are defined as hybrid devices (expressed in the miscdevice structure ). Miscdevice shares the primary device number MISC_MAJOR (10), but the secondary device number is different. All miscdevice devices form a linked list. During device access, the kernel searches for the corresponding miscdevice device based on the device number, and then calls the file operation interface registered in its file_operations structure to perform operations. In the kernel, use struct miscdevice to represent the miscdevice device, and then call the file operation interface registered in its file_operations structure to perform operations. The API of miscdevice is implemented in drivers/char/misc. c. The initialization, registration, and logout of the misc device are all in this file. In the kernel, The misc miscellaneous device driver interface is a simple encapsulation of some character devices. They share a master device number with different sub-device numbers and share an open call, other operating functions are loaded using the linux driver method after being turned on.
First, let's look at the structure description of the misc device:
The code is located in android-4.1/kernel/include/linux/miscdevice. h. This file also contains the macro definition of the sub-device Number of all misc devices.
Struct miscdevice {intminor; // device number const char * name; // device name const structfile_operations * fops; // file operation structlist_head list; // The chain table header of misc_list struct device * parent; // parent device (Dongdong in the Linux device model, haha) struct device * this_device; // The current device is the return value of device_create, the following shows constchar * nodename; mode_tmode ;};
This struct is the basic struct of the misc device. When registering an misc device, you must declare and initialize this struct. However, you only need to fill in the name minor fops field. The following code initializes miscdevice In the led driver:
static struct miscdevice misc = { .minor =MISC_DYNAMIC_MINOR, .name =DEVICE_NAME, .fops =&dev_fops, };
Generally, you do not need to implement the open method in fops, because the initial method misc_ops contains the open method. If minor is filled with MISC_DYNAMIC_MINOR, the device number is dynamically assigned by misc_register.
Then let's take a look at the initialization function of the misc subsystem:
Static int _ init misc_init (void) {int err; # ifdef CONFIG_PROC_FS proc_create ("misc", 0, NULL, & misc_proc_fops ); /* Create a proc entry */# endif misc_class = class_create (THIS_MODULE, "misc "); /* create a class named misc under the/sys/class/directory */err = PTR_ERR (misc_class); if (IS_ERR (misc_class) gotofail_remove; err =-EIO; /* register the device. The master device Number of the device is MISC_MAJOR, which is 10. The device name is misc, and misc_fops is the set of operation functions */if (condition (MISC_MAJOR, "misc", & misc_fops) gotofail_printk; misc_class-> devnode = misc_devnode; return0; fail: printk ("unable to get major % d for misc devices/n", MISC_MAJOR); class_destroy (misc_class); fail_remove: remove_proc_entry ("misc", NULL); returnerr ;} subsys_initcall (misc_init);/* misc is registered as a sub-system in the Linux Kernel */
We can see that the main function of this initialization function is to register character devices. The registration interface used is the register_chrdev of the 2.4 kernel. It registers 256 devices with the primary device number "MISC_MAJOR" and the secondary device number "0. A misc class is created.
Below is the implementation of the register_chrdev function:
Int register_chrdev (unsigned int major, const char * name, const struct file_operations * fops) {structchar_device_struct * cd; struct cdev * cdev; char * s; int err =-ENOMEM; /* if the master device number is 10 and the secondary device number starts from 0, 256 devices are allocated */cd = __register_chrdev_region (major, 0,256, name); if (IS_ERR (cd )) returnPTR_ERR (cd);/* assign character device */cdev = cdev_alloc (); if (! Cdev) gotoout2; cdev-> owner = fops-> owner; cdev-> ops = fops;/* in the Linux device model, set the kobject name */kobject_set_name (& cdev-> kobj, "% s", name); for (s = strchr (kobject_name (& cdev-> kobj ), '/'); s = strchr (s, '/') * s = '! ';/* Register the device with this character in the system */err = cdev_add (cdev, MKDEV (cd-> major, 0), 256); if (err) gotoout; cd-> cdev = cdev; return major? 0: cd-> major; out: kobject_put (& cdev-> kobj); out2: kfree (_ unregister_chrdev_region (cd-> major, 0,256); returnerr ;} let's take a look at the set of operation functions for this device: static const struct file_operations misc_fops = {. owner = THIS_MODULE ,. open = misc_open ,};
You can see that there is only one open function. the user opens the miscdevice device through the open function corresponding to the master device number. In this function, find the corresponding open function of the specific device corresponding to the next device number. Its implementation is as follows:
Static int misc_open (struct inode * inode, struct file * file) {intminor = iminor (inode); structmiscdevice * c; interr =-ENODEV; const struct file_operations * old_fops, * new_fops = NULL; lock_kernel (); mutex_lock (& misc_ctx);/* Find the set of operation functions corresponding to the next device number, set new_fops to the operation function set of the specific device */list_for_each_entry (c, & misc_list, list) {if (c-> minor = minor) {new_fops = fops_get (c-> fops); break ;}} if (! New_fops) {mutex_unlock (& misc_ctx);/* if not found, request to load the module */request_module ("char-major-% d", MISC_MAJOR, minor); mutex_lock (& misc_ctx ); /* re-traverse the misc_list linked list. Exit if not found; otherwise, point new_fops to the operation function set of the specific device */list_for_each_entry (c, & misc_list, list) {if (c-> minor = minor) {new_fops = fops_get (c-> fops); break ;}} if (! New_fops) goto fail;} err = 0;/* Save the address of the old OPEN function */old_fops = file-> f_op; /* set the operation function set pointer of the master device number to the operation function set of the specific device */file-> f_op = new_fops; if (file-> f_op-> open) {/* use the open function of a specific device to open the device */err = file-> f_op-> open (inode, file); if (err) {fops_put (file-> f_op); file-> f_op = fops_get (old_fops) ;}} fops_put (old_fops); fail: mutex_unlock (& misc_xr); unlock_kernel (); return err ;}
Let's take a look at the two important APIs provided by the misc subsystem: misc_register and misc_deregister:
The misc_register () function is in misc. in c, the main function is to construct a device based on misc_class, mount the miscdevice structure to the misc_list list, and initialize the structure related to the linux device model. Its parameter is the miscdevice structure.
Int misc_register (struct miscdevice * misc) {struct miscdevice * c; dev_t dev; interr = 0; INIT_LIST_HEAD (& misc-> list ); // mutex_lock (& misc_ctx) must be initialized when using linked list items;/* traverse the misc_list linked list to see if the device number has been used before, if the device number is occupied, exit */list_for_each_entry (c, & misc_list, list) {if (c-> minor = misc-> minor) {mutex_unlock (& misc_ctx); return-EBUSY ;}}/* check whether the device number needs to be dynamically allocated. */if (misc-> minor = MISC_DYNAMIC_MINOR) {/** # define DYNAMIC _ MINORS 64/* like dynamic majors */* static unsigned char misc_minors [DYNAMIC_MINORS/8]; * There is a device number bitmap, a total of 64 bits. Below is the traversal of each bit. * if this value is 0, it indicates that it is not occupied. You can use it. If it is 1, it indicates that it is occupied. */Int I = DYNAMIC_MINORS; while (-- I> = 0) if (misc_minors [I> 3] & (1 <(I & 7 ))) = 0) break; if (I <0) {mutex_unlock (& misc_ctx); return-EBUSY ;} /* get the device Number */misc-> minor = I;}/* set the bitmap to 1 */if (misc-> minor <DYNAMIC_MINORS) misc_minors [misc-> minor> 3] | = 1 <(misc-> minor & 7);/* calculate the device Number */dev = MKDEV (MISC_MAJOR, misc-> minor);/* create a device node under/dev, which means some drivers do not explicitly call device_create, the cause of the device node is displayed */misc-> this_device = device_create (misc_class, misc-> parent, dev, NULL, "% s", misc-> name ); if (IS_ERR (misc-> this_device) {err = PTR_ERR (misc-> this_device); goto out;}/** Add it to the front, so that later devices can "override" * earlier ults * // * Add this miscdevice to the misc_list linked list */list_add (& misc-> list, & misc_list); out: mutex_unlock (& misc_ctx); return err ;}
We can see that this function first traverses the misc_list linked list and finds whether the device number used has been registered to prevent conflict. If it is a dynamic device number, allocate a device number and call MKDEV to generate the device number. From this we can see that all misc devices share a master device number MISC_MAJOR, and then call device_create to generate a device file. Finally, add it to the misc_list linked list.
About the function of device_create and class_create: The class_create function is called during module initialization in misc. c. Let's talk about it now. These two functions seem unfamiliar and have not been found in ldd3. when looking at the source code, class_create will call the underlying component _ class_regsiter (), which indicates that it is registering a class. Device_create is used to create a device. It is convenient to create a device and calls the device_register function. They are all provided for linux device models. After a linux kernel version of 2.6, devfs no longer exists and udev becomes a replacement for devfs. Compared with devfs, udev has many advantages.
Struct class * myclass = class_create (THIS_MODULE, "my_device_driver ");
Class_device_create (myclass, NULL, MKDEV (major_num, 0), NULL, "my_device ");
In this way, a class and device are created. When a module is loaded, udev daemon automatically creates the my_device file node under/dev. This saves the trouble of creating device files by yourself. This also facilitates the management of Dynamic devices.
This is the uninstall function of miscdevice:
Int misc_deregister (struct miscdevice * misc) {inti = misc-> minor; if (list_empty (& misc-> list) return-EINVAL; mutex_lock (& misc_ctx ); /* Delete the miscdevice device */list_del (& misc-> list) in the misc_list;/* Delete the device node */device_destroy (misc_class, MKDEV (MISC_MAJOR, misc-> minor); if (I <DYNAMIC_MINORS & I> 0) {/* release the corresponding bitmap bit */misc_minors [I> 3] & = ~ (1 <(misc-> minor & 7);} mutex_unlock (& misc_ctx); return 0 ;}
Summarize the registration and uninstallation processes of the miscdevice DRIVER:
Misc_register) -> calculate the device number-> Create a device file-> Add the miscdevice struct to the misc_list linked list.
Misc_deregister: delete miscdevice from mist_list> Delete Device File> clear bitmap.
Summary:
As the encapsulation of character devices, Miscellaneous devices provide simple programming interfaces for character devices. if you write a new character driver, you can consider using interfaces of Miscellaneous devices for convenience and simplicity, you only need to initialize the structure of a miscdevice and call misc_register. The system has a maximum of 255 Miscellaneous devices, because the module occupies one device number.