MISC means mixed and miscellaneous, so MISC driver is also called miscellaneous driver, that is, when we have a driver on the board
When some peripherals cannot be classified, MISC driver can be used.
MISC driver is actually the simplest character device driver. It is usually nested in platform bus driver to realize complex driver
1, Introduction to MISC device driver
The master device number of all MISC device drivers is 10, and different devices use different slave device numbers. With Linux
With the increasing number of character device drivers, the device number becomes more and more tense, especially the main device number. MISC device driver is used to solve this problem. MISC device will automatically create cdev, which does not need to be created manually as before. Therefore, using MISC device driver can simplify the writing of character device driver.
We need to register a miscdevice device with Linux. Miscdevice is a structure defined in the file include / Linux / miscdevice H, as follows:
57 struct miscdevice { 58 int minor; /* Sub equipment No */ 59 const char *name; /* Device name */ 60 const struct file_operations *fops; /* Device operation set */ 61 struct list_head list; 62 struct device *parent; 63 struct device *this_device; 64 const struct attribute_group **groups; 65 const char *nodename; 66 umode_t mode; 67 };
After defining a MISC device (miscdevice type), we need to set three member variables: minor, name and fops. Minor refers to the sub device number. The main device number of MISC device is 10. This is fixed and needs to be specified by the user. The Linux system has predefined some sub device numbers of MISC devices, which are defined in include / Linux / miscdevice H file, as follows:
13 #define PSMOUSE_MINOR 1 14 #define MS_BUSMOUSE_MINOR 2 /* unused */ 15 #define ATIXL_BUSMOUSE_MINOR 3 /* unused */ 16 /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ 17 #define ATARIMOUSE_MINOR 5 /* unused */ 18 #define SUN_MOUSE_MINOR 6 /* unused */ ...... 52 #define MISC_DYNAMIC_MINOR 255
When using, we can select one of these predefined sub equipment numbers. Of course, we can also define it ourselves, as long as
This sub device number is not used by other devices.
Name is the name of the MISC device. After the device is registered successfully, a device file named name will be generated in the / dev directory.
fops is the operation set of character devices,
MISC device driver finally needs to use the fops operation set provided by the user.
After setting miscdevice, you need to use MISC_ The register function registers a MISC device with the system
The function prototype is as follows:
int misc_register(struct miscdevice * misc)
Function parameters and return values have the following meanings:
MISC: MISC device to register.
Return value: negative number, failed; 0, successful.
In the past, we needed to call a bunch of functions to create devices. For example, we used it in the previous character device driver
The following functions complete the device creation process:
1 alloc_chrdev_region(); /* Application equipment No */ 2 cdev_init(); /* Initialize cdev */ 3 cdev_add(); /* Add cdev */ 4 class_create(); /* Create class */ 5 device_create(); /* Create device */
Now we can use misc directly_ Register a function to complete these steps in the sample code. When I
When you uninstall the device driver module, you need to call misc_deregister function to log off the MISC device. The function prototype is as follows:
int misc_deregister(struct miscdevice *misc)
Function parameters and return values have the following meanings:
MISC: MISC device to log off.
Return value: negative number, failed; 0, successful.
Before logging off the device driver, we need to call a bunch of functions to delete the previously created cdev, device, etc
Capacity, as follows:
1 cdev_del(); /* Delete cdev */ 2 unregister_chrdev_region(); /* Logout equipment number */ 3 device_destroy(); /* Delete device */ 4 class_destroy(); /* Delete class */
Now we just need a misc_ The deregister function does this in the sample code.
That's all for MISC device driver. Next, we'll use platform and MISC driver framework to write beep buzzer driver.
2, Hardware schematic analysis
3, Experimental programming
In this chapter, we use platform plus misc to write beep driver, which is also a common method in actual Linux driver. Platform is used to realize bus, device and driver, and misc is mainly responsible for the creation of character device.
1. Modify the equipment tree
The beep device node has been created before
2.beep driver programming
Create a new folder named "19_miscbeep", and then_ Create a vscode project in the miscbeep folder, and the workspace is named "miscbeep". Create a new driver file named miscbeep.c, and enter the following contents in miscbeep.c:
#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/gpio.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <asm/mach/map.h> #include <asm/uaccess.h> #include <asm/io.h> /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. file name : miscbeep.c author : Zuo Zhongkai edition : V1.0 describe : Buzzer driver using MISC. other : nothing Forum : www.openedv.com journal : First edition v1 0 created by Zuo Zhongkai on August 20, 2019 ***************************************************************/ #define MISCBEEP_NAME "miscbeep" /* name */ #define MISCBEEP_MINOR one hundred and forty-four /* Sub equipment No*/ #define BEEPOFF 0 /* Turn off the buzzer*/ #define BEEPON one /* Turn on the buzzer*/ /* miscbeep Equipment structure */ struct miscbeep_dev{ dev_t devid; /* Equipment number */ struct cdev cdev; /* cdev */ struct class *class; /* class */ struct device *device; /* equipment */ struct device_node *nd; /* Device node */ int beep_gpio; /* beep GPIO number used */ }; struct miscbeep_dev miscbeep; /* beep equipment */ /* * @description : open device * @param - inode : inode passed to driver * @param - filp : The device file has a file structure called private_ Member variable of data * Generally, private is used when open ing_ Data points to the device structure. * @return : 0 success; Other failures */ static int miscbeep_open(struct inode *inode, struct file *filp) { filp->private_data = &miscbeep; /* Set private data */ return 0; } /* * @description : Write data to device * @param - filp : A device file that represents an open file descriptor * @param - buf : Data to write to device * @param - cnt : Length of data to write * @param - offt : Offset relative to the first address of the file * @return : The number of bytes written. If it is negative, it indicates that the write failed */ static ssize_t miscbeep_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[1]; unsigned char beepstat; struct miscbeep_dev *dev = filp->private_data; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0) { printk("kernel write failed!\r\n"); return -EFAULT; } beepstat = databuf[0]; /* Get status value */ if(beepstat == BEEPON) { gpio_set_value(dev->beep_gpio, 0); /* Turn on the buzzer */ } else if(beepstat == BEEPOFF) { gpio_set_value(dev->beep_gpio, 1); /* Turn off the buzzer */ } return 0; } /* Device operation function */ static struct file_operations miscbeep_fops = { .owner = THIS_MODULE, .open = miscbeep_open, .write = miscbeep_write, }; /* MISC Equipment structure */ static struct miscdevice beep_miscdev = { .minor = MISCBEEP_MINOR, .name = MISCBEEP_NAME, .fops = &miscbeep_fops, }; /* * @description : flatform Driven probe function, when driven with * This function will be executed after the device matches * @param - dev : platform equipment * @return : 0,success; Other negative values, failed */ static int miscbeep_probe(struct platform_device *dev) { int ret = 0; printk("beep driver and device was matched!\r\n"); /* Set the GPIO used by BEEP */ /* 1,Get device node: beep */ miscbeep.nd = of_find_node_by_path("/beep"); if(miscbeep.nd == NULL) { printk("beep node not find!\r\n"); return -EINVAL; } /* 2, Get the gpio attribute in the device tree and get the BEEP number used by BEEP */ miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpio", 0); if(miscbeep.beep_gpio < 0) { printk("can't get beep-gpio"); return -EINVAL; } /* 3,Set GPIO5_IO01 is output and outputs high level. BEEP is turned off by default */ ret = gpio_direction_output(miscbeep.beep_gpio, 1); if(ret < 0) { printk("can't set gpio!\r\n"); } /* Generally, the corresponding character device will be registered, but here we use MISC device * So we don't need to register the character device driver ourselves, we just need to register the misc device driver */ ret = misc_register(&beep_miscdev); if(ret < 0){ printk("misc device register failed!\r\n"); return -EFAULT; } return 0; } /* * @description : platform The remove function of the platform driver. This function will be executed when the platform driver is removed * @param - dev : platform equipment * @return : 0,success; Other negative values, failed */ static int miscbeep_remove(struct platform_device *dev) { /* Turn off the LED when logging off the device */ gpio_set_value(miscbeep.beep_gpio, 1); /* Unregister misc device */ misc_deregister(&beep_miscdev); return 0; } /* Match list */ static const struct of_device_id beep_of_match[] = { { .compatible = "atkalpha-beep" }, { /* Sentinel */ } }; /* platform Drive structure */ static struct platform_driver beep_driver = { .driver = { .name = "imx6ul-beep", /* Driver name, used to match the device */ .of_match_table = beep_of_match, /* Device tree matching table */ }, .probe = miscbeep_probe, .remove = miscbeep_remove, }; /* * @description : Drive exit function * @param : nothing * @return : nothing */ static int __init miscbeep_init(void) { return platform_driver_register(&beep_driver); } /* * @description : Drive exit function * @param : nothing * @return : nothing */ static void __exit miscbeep_exit(void) { platform_driver_unregister(&beep_driver); } module_init(miscbeep_init); module_exit(miscbeep_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");
Lines 29-94, standard character device driver.
Lines 97-101, MISC equipment beep_miscdev,
Line 98 sets the sub equipment number to 144,
In line 99, set the device name to "miscbeep", so that when the system starts, there will be a device file named "miscbeep" in the / dev / directory.
Line 100: set the operation function set of MISC device to file_operations type.
Lines 109 to 145 are the probe function of the platform framework. This function will be executed after the driver matches the device. First
Initializes the IO used by BEEP in this function.
Finally, MISC is passed on line 138_ The register function registers the MISC device with the Linux kernel, that is, the beep defined earlier_ miscdev.
Line 152~160, the remove function of the platform framework, calling misc_ in this function. Deregister function to log off
MISC equipment.
163 ~ 196, standard platform driver.
3. Write test APP
Create a new miscbeepapp C file, and then enter the following contents in it:
#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. file name : miscbeepApp.c author : Zuo Zhongkai edition : V1.0 describe : beep test APP under MISC driven framework. other : nothing usage method : ./ Miscbeepapp / dev / miscbeep 0 turn off the buzzer ./misdcbeepApp /dev/miscbeep 1 Turn on the buzzer Forum : www.openedv.com journal : First edition v1 0 created by Zuo Zhongkai on August 20, 2019 ***************************************************************/ #define BEEPOFF 0 #define BEEPON 1 /* * @description : main main program * @param - argc : argv Number of array elements * @param - argv : Specific parameters * @return : 0 success; Other failures */ int main(int argc, char *argv[]) { int fd, retvalue; char *filename; unsigned char databuf[1]; if(argc != 3){ printf("Error Usage!\r\n"); return -1; } filename = argv[1]; fd = open(filename, O_RDWR); /* Turn on beep driver */ if(fd < 0){ printf("file %s open failed!\r\n", argv[1]); return -1; } databuf[0] = atoi(argv[2]); /* What to do: turn on or off */ retvalue = write(fd, databuf, sizeof(databuf)); if(retvalue < 0){ printf("BEEP Control Failed!\r\n"); close(fd); return -1; } retvalue = close(fd); /* Close file */ if(retvalue < 0){ printf("file %s close failed!\r\n", argv[1]); return -1; } return 0; }
4, Run test
depmod //This command needs to be run when the driver is loaded for the first time modprobe miscbeep.ko //Load device module
After the driver module is loaded successfully, we can see a file named "miscbeep" in the directory / sys/class/misc
As shown in the figure:
All misc devices belong to the same class. All misc devices in the / sys/class/misc directory correspond to a subdirectory.
After the driver matches the device successfully, the device driver file / dev/miscbeep will be generated. Enter the following command to view this file
Primary and secondary device numbers of files:
ls /dev/miscbeep -l
/dev/miscbeep the primary device number of this device is 10 and the secondary device number is 144, which is consistent with the settings in our driver.
Open BEEP by entering the following command:
./miscbeepApp /dev/miscbeep 1 //Open BEEP