Misc Subsystem
Reprint Please specify source: Http://blog.csdn.net/wang_zheng_kai
Institute of Light source devices and systems
Summary of individual Learning
1. What is misc in the Linux system?
When researching the camera driver, we found that the path of the camera driver is:/driver/misc/jz_cim/file directory, after the search results are as follows:
Miscellaneous equipment (Misc device)
Miscellaneous equipment is also used in embedded systems more than a device driver. There are miscdevice.h files in the Include/linux directory of the Linux kernel, where you define your own Misc devices from the device. In fact, because these character devices do not conform to the pre-determined character device category, all of these devices use the main Number 10, together with Misc device, in fact, Misc_register is the main label 10 calls Register_chrdev (), But misc is to store 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 analysis
A variety of devices that cannot be categorized are defined as hybrid devices (expressed in the Miscdevice structure) in a Linux drive. Miscdevice shares a master device number Misc_major (that is, 10), but the secondary device number is different. All Miscdevice devices form a linked list, and the kernel locates the corresponding Miscdevice device according to the secondary device number when the device accesses it, and then invokes the file operation interface registered in its file_operations structure. The Miscdevice device is represented in the kernel with a struct miscdevice and then invoked by the file operation interface registered in its file_operations structure. Miscdevice API implementation in drivers/char/misc.c , misc device Initialization, registration, logoff are 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, have different secondary device numbers, share an open call, and other operation functions are loaded using the method overloads of the Linux driver after opening.
Let's first look at the description of the structure of the misc device:
The code is located in: Android-4.1/kernel/include/linux/miscdevice.h, which also has a macro definition of the secondary device number for all misc devices.
struct Miscdevice { intminor; Second device number const char*name; The name of the device is const structfile_operations *fops; File operations structlist_head list; Misc_list's chain-head struct device*parent; Parent device (the Linux device model in the east, haha) struct device*this_device; Current device, is the return value of Device_create, below will see Constchar *nodename;
This structure is the basic structure of the Misc device, it is necessary to declare and initialize a struct when registering the misc device, but it is generally only possible to populate the name minor FoPs field. The following is the code that initializes the miscdevice in the LED driver:
static struct Miscdevice misc = { . minor =misc_dynamic_minor, . Name =device_name,
In general, there is no need to implement the Open method in FoPs, because the initial method Misc_ops contains the open method. Where MINOR is populated with Misc_dynamic_minor, it is a dynamic secondary device number, and the secondary device number is dynamically assigned by Misc_register.
Then 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 in the/sys/class/directory * /err = Ptr_err (misc_class); if (Is_err (misc_class)) Gotofail_remove; Err =-eio; /* Register the device, where the device's main device number is misc_major, which is 10. The device name Misc,misc_fops is the set of operation functions * /if (Register_chrdev (Misc_major, "misc", &misc_fops)) GOTOFAIL_PRINTK; Misc_class->devnode= Misc_devnode; Return0; FAIL_PRINTK: 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);
As can be seen, this initialization function, the most important function is to register the character device, the registration interface used is the 2.4 kernel Register_chrdev. It registered 256 devices with a main device number of misc_major and a secondary device number of 0-255. And a Misc class was 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_struc T *CD; struct Cdev*cdev; Char *s; int err =-enomem; /* The main device number is 10, the secondary device number starts from 0, 256 devices are allocated */CD =__register_chrdev_region (major, 0,, 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 name of Kobject */Kobject_set_name (&cdev->kobj, "%s", name); for (S =STRCHR (Kobject_name (&cdev->kobj), '/'); s = STRCHR (S, '/')) *s = '! '; /* Register this character device 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; Take a look at the collection of operation functions for this device: static const struct File_operations Misc_fops = {. Owner =this_module,. Open = Misc_open,};
You can see there is only one open function, the user opens the Miscdevice device is the main device number corresponding to the open function, in this function to find the secondary device number corresponding to the corresponding specific device's open function. It is implemented 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_MTX); /* Find the corresponding set of operation functions for the secondary device number, and let New_fops point to the set of operating functions for this 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_MTX); /* If not found, then request to load this secondary device number corresponding to the module */request_module ("char-major-%d-%d", misc_major, minor); Mutex_lock (&MISC_MTX); /* Re-traverse the Misc_list list, exit if not found, otherwise let new_fops point to the specific device's set of operations function */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 address for old open function */old_fops = file->f_op; /* Let the operation function set pointer of the main device number point 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_MTX); Unlock_kernel (); return err; }
Then take a look at two important api,misc_register,misc_deregister that the misc subsystem provides externally:
The main function of the Misc_register () function in MISC.C is to construct a device based on Misc_class, attach the miscdevice structure to the Misc_list list, and initialize the structure associated with the Linux device model. Its parameter is the MISCDEVICE structure body.
int Misc_register (struct miscdevice *misc) {struct Miscdevice *c; dev_t Dev; Interr = 0; Init_list_head (&misc->list); The Mutex_lock (&MISC_MTX) must be initialized when the list item is used; /* Traverse the misc_list list to see if the device number has been used before, and if the secondary device number is already occupied then exit */List_for_each_entry (c, &misc_list, list) {if (C->minor = = Misc->minor) {mutex_unlock (&MISC_MTX); Return-ebusy; }/* See if it is necessary to allocate the secondary device number dynamically */if (Misc->minor = = Misc_dynamic_minor) {/* * #define DYNAMIC_MINORS 64 /* Like dynamic majors */*static unsigned char MISC_MINORS[DYNAMIC_MINORS/8]; * There is a secondary device number bitmap, altogether 64 bits. Below is the traversal of each bit, * if this is 0, the representation is not occupied, can be used, for 1 is occupied. */int i = dynamic_minors; while (---->= 0) if ((Misc_minors[i>>3] & (1 << (i&7)) = = 0) break; if (i<0) {mutex_unlock (&MISC_MTX); Return-ebusy; }/* Get this secondary device number*/Misc->minor = i; }/* Set the corresponding bit in the bitmap to 1*/if (Misc->minor < dynamic_minors) Misc_minors[misc->minor >> 3] |= 1 <& Lt (misc->minor& 7); /* Calculate the device number */dev= MKDEV (Misc_major, Misc->minor); /* Create a Device node under/dev, which is why some drivers do not explicitly call device_create, but there is a reason for the device node */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, later devices can "override" *earlier defaults */* will this Miscdev Ice added to misc_list linked list */List_add (&misc->list, &misc_list); Out:mutex_unlock (&MISC_MTX); return err; }
As you can see, this function first traverses the Misc_list list to find out if the secondary device number used has been registered to prevent collisions. If the dynamic secondary device number is assigned one, then call Mkdev to generate the device number, from which you can see that all the Misc devices share a master device number Misc_major, and then call Device_create to generate the device file. Finally added to the misc_list linked list.
About Device_create,class_create function: The Class_create function is called in the initialization of the module in MISC.C, and now let's talk about it. These two functions look strange, not found in the LDD3, when looking at the source code to find that Class_create will invoke the underlying component __class_regsiter () is to indicate that it is registering a class. While Device_create is creating a device, he is a convenient implementation of creating devices called the Device_register function. They are all available to the Linux device model, and after a version of Linux kernel 2.6, DEVFS no longer exists, and Udev becomes an alternative to DEVFS. There are many advantages over Devfs,udev.
struct class *myclass =class_create (This_module, "my_device_driver");
Class_device_create (MyClass, Null,mkdev (major_num, 0), NULL, "My_device");
This creates a class and device, and when the module is loaded, Udev daemon automatically creates the My_device device file node in/dev. This eliminates the hassle of creating your own device files. This also facilitates the management of dynamic devices.
This is the Unload function of Miscdevice:
int Misc_deregister (struct Miscdevice*misc) { inti = misc->minor; if (List_empty (&misc->list)) Return-einval; Mutex_lock (&MISC_MTX); /* Delete the Miscdevice device in the misc_list list * /List_del (&misc->list); /* Delete Device node * /Device_destroy (Misc_class, MKDEV (Misc_major, Misc->minor)); if (i < dynamic_minors && i>0) {/ * free bitmap corresponding bit */ misc_minors[i>>3] &= ~ (1 << (misc-& Gt;minor &7)); } Mutex_unlock (&MISC_MTX); return 0; }
Summarize the Miscdevice driver registration and uninstallation process:
Misc_register: Match secondary device number, find an unoccupied secondary device number (if dynamic allocation is required)--Create a device file->miscdevice the structure body added to the misc_list linked list.
Misc_deregister: Remove the bitmap bit zeroing from the Mist_list miscdevice-> delete device files.
Summarize:
Miscellaneous devices as the encapsulation of character devices, for the character device provides a simple programming interface, if you write a new character driver, you can consider the use of miscellaneous device interface, convenient and simple, only need to initialize a miscdevice structure, call Misc_register can be. The system has a maximum of 255 miscellaneous devices because the Miscellaneous device module itself occupies a secondary device number
Misc Subsystem in Linux system