Disclaimer: This article is a blog of liufazhang, an open-source Chinese community.
In Linux, there is a type of character device that shares a master device number (10), but this device number is different. We call this type of device as a hybrid device (miscdeivce ), view/proc/device, and you can see that the master device Number of misc is 10. all the hybrid devices form a linked list. During device access, the kernel finds the corresponding miscdevice device based on the next device number.
The Linux kernel uses struct miscdeivce to describe a Hybrid device.
Struct miscdevice {
Int minor;
Const char * name;
Const struct file_operations * fops;
Struct list_head list;
Struct device * parent;
Struct device * this_device;
Const char * nodename;
Mode_t mode;
};
Minor is the sub-device number of this hybrid device. If it is automatically configured by the system, it can be set to MISC_DYNANIC_MINOR, and name is the device name. you only need to enter the minor device number, * name device name, and * fops file operation function set.
The Linux kernel uses the misc_register function to register a Hybrid device and uses misc_deregister to remove a Hybrid device. After the registration is successful, the Linux kernel automatically creates a device node for the device, and a corresponding node is generated under/dev.
Registration function:
Int misc_register (struct miscdevice * misc)
Input parameter: struct miscdevice
Return Value:
Indicates that the registration is successful.
A negative number indicates that the operation failed.
Unmount function:
Int misc_deregister (struct miscdevice * misc)
0 indicates success.
Negative number indicates failure.
The following is a simple example of a linux Hybrid device model:
View sourceprint? 01 # include <linux/module. h>
02 # include <linux/kernel. h>
03 # include <linux/types. h>
04 # include <linux/fs. h>
05 # include <linux/init. h>
06 # include <linux/delay. h>
07 # include <asm/uaccess. h>
08 # include <asm/irq. h>
09 # include <asm/io. h>
10 # include <linux/cdev. h>
11 # include <linux/device. h>
12 # include <linux/miscdevice. h>
13 # define DEVICE_NAME "BELL-Control"
14 volatile unsigned long * gpbcon = NULL;
15 volatile unsigned long * gpbdat = NULL;
16 volatile unsigned long * gpbup = NULL;
17 static int bell_drv_open (struct inode * inode, struct file * file)
18 {
19 * gpbcon & = ~ (0x3 <(0*2 ));
20 * gpbcon | = (0x1 <(0*2 ));
21 * gpbup = 0x0;
22 printk ("first_drv_open \ n ");
23 return 0;
24}
25
26 static ssize_t bell_drv_write (struct file * file, const char _ user * buf, size_t count, loff_t * ppos)
27 {
28 int val;
29 copy_from_user (& val, buf, count );
30 if (val = 1)
31 {
32 * gpbdat & = ~ (1 <0 );
33 printk ("first_drv_write 1111111 \ n ");
34}
35 else
36 {
37
38 * gpbdat | = (1 <0 );
39 printk ("first_drv_write 00000 \ n ");
40}
41 return 0;
42}
43
44 static struct file_operations bell_drv_fops = {
45. owner = THIS_MODULE,/* This is a macro. The _ this_module variable is automatically created when it is pushed to the compilation module */
46. open = bell_drv_open,
47. write = bell_drv_write,
48 };
49 // register a Hybrid device. Each misc driver automatically appears under/sys/class/misc /.
50 static struct miscdevice misc = {
51. minor = MISC_DYNAMIC_MINOR,
52. name = DEVICE_NAME,
53. fops = & bell_drv_fops,
54 };
55
56 static int bell_drv_init (void)
57 {
58 int result;
59 result = misc_register (& misc );
60 printk ("" DEVICE_NAME "initialized \ n ");
61 gpbcon = (volatile unsigned long *) ioremap (0x56000010, 16 );
62 gpbdat = gpbcon + 1;
63 gpbup = gpbcon + 2;
64 return 0;
65}
66
67 static void bell_drv_exit (void)
68 {
69 misc_deregister (& misc );
70 iounmap (gpbcon );
71}
72
73 module_init (bell_drv_init );
74 module_exit (bell_drv_exit );
75 MODULE_LICENSE ("GPL ");