嵌入式学习笔记–misc
一、内核自带MISC驱动简介
misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。 MISC 驱动其实就是最简单的字符设备驱动,通常嵌套在 platform 总线驱动中,实现复杂的驱动,
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号, MISC 设备驱动就用于解决此问题。 MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。
MISC驱动编写的核心就是初始化miscdevice结构体变量。然后使用misc_register向内核注册,卸载驱动的时候使用misc_deregister来卸载miscdevice。 如果设置miscdevice里面minor为255的话,表示由内核自动分配也给次设备号。
二、驱动实例
#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>
#define MISCBEEP_NAME "miscbeep" /* 名字 */
#define MISCBEEP_MINOR 144 /* 子设备号 */
#define BEEPOFF 0 /* 关蜂鸣器 */
#define BEEPON 1 /* 开蜂鸣器 */
struct misc_devices {
struct device_node *dev_node;
int beep_gpio;
};
struct misc_devices *misc_dev;
static int miscbeep_open(struct inode *inod, struct file *filp){
printk("-----------%s------------\n",__FUNCTION__);
filp->private_data = misc_dev;
return 0;
}
static ssize_t miscbeep_read(struct file *filp, char __user *buf, size_t size, loff_t *loft){
printk("-----------%s------------\n",__FUNCTION__);
return 0;
}
static ssize_t miscbeep_write(struct file *filp, const char __user *buf, size_t size, loff_t *loft){
printk("-----------%s------------\n",__FUNCTION__);
int ret;
unsigned char databuf[1];
struct misc_devices *dev = filp->private_data;
ret = copy_from_user(databuf, buf, size);
if(ret<0){
printk("kernel write failed!!\n");
return -EFAULT;
}
if(databuf[0] == BEEPON){
gpio_set_value(dev->beep_gpio,0);
}else if(databuf[0] == BEEPOFF){
gpio_set_value(dev->beep_gpio,1);
}
return 0;
}
static int miscbeep_release(struct inode *inod, struct file *filp){
printk("-----------%s------------\n",__FUNCTION__);
return 0;
}
//004-2
static struct file_operations miscbeep_fops = {
.owner = THIS_MODULE,
.open = miscbeep_open,
.read = miscbeep_read,
.write = miscbeep_write,
.release = miscbeep_release,
};
//004-1
static struct miscdevice misc_beep = {
.minor = 144,//次设备号。主设备号系统已经提供,为10
.name = "miscbeep",//设备的名字。 加载驱动成功后,/dev/下会出现miscbeep这个设备
.fops = &miscbeep_fops,
};
//03-1
static int misc_probe(struct platform_device *dev){
printk("device and driver has matched!!\n");
misc_dev = (struct misc_devices *)kzalloc(sizeof(struct misc_devices),GFP_KERNEL);
if(misc_dev == NULL){
printk("misc_dev alloc failed!!\n");
return -ENOMEM;
}
int ret = 0;
//001.获取设备节点
misc_dev->dev_node = of_find_node_by_path("/gpio_beep");
if(misc_dev->dev_node == NULL){
printk("beep node not find!!\n");
return -EINVAL;
}
//002.获取设备树中gpio属性,gpio号
misc_dev->beep_gpio = of_get_named_gpio(misc_dev->dev_node, "beep-gpio", 0);
if(misc_dev->beep_gpio < 0){
printk("beep_gpio can not get!!\n");
return -EINVAL;
}
printk("beep-gpio %d !!\n",misc_dev->beep_gpio);
///003.设置gpio为输出,1为输出高电平
ret = gpio_direction_output(misc_dev->beep_gpio, 1);
if(ret<0){
printk("can not set gpio!!\n");
}
//004.
ret = misc_register(&misc_beep);
if(ret < 0){
printk("misc device register failed!!\n");
return -EINVAL;
}
printk("------misc_probe done!----\n");
return 0;
}
//03-2
static int misc_remove(struct platform_device *dev){
gpio_set_value(misc_dev->beep_gpio,1);
misc_deregister(&misc_beep);
kfree(misc_dev);
return 0;
}
const struct of_device_id misc_of_match[] = {
{.compatible = "peifeng-gpiobeep"},//和设备树中的compatible应该一至
{}
};
//03.
struct platform_driver misc_drv = {
.driver = {
.name = "peifeng-gpiobeep",
.of_match_table = misc_of_match,
},
.probe = misc_probe,
.remove = misc_remove,
};
//01.
static int __init misc_drv_init(void){
printk("-----------%s------------\n",__FUNCTION__);
return platform_driver_register(&misc_drv);
}
//02.
static void __exit misc_drv_exit(void){
printk("-----------%s------------\n",__FUNCTION__);
return platform_driver_unregister(&misc_drv);
}
module_init(misc_drv_init);
module_exit(misc_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("PEIFENG");
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#define MISCBEEP_NAME "miscbeep" /* 名字 */
#define MISCBEEP_MINOR 144 /* 子设备号 */
#define BEEPOFF 0 /* 关蜂鸣器 */
#define BEEPON 1 /* 开蜂鸣器 */
int main(int argc,char *argv[]){
int fd,ret;
unsigned databuf[1];
if(argc<3){
printf("error useage!! please ./** /dev/miscbeep 1");
return -1;
}
fd = open(argv[1],O_RDWR);
if(fd<0){
printf("file %s open failed!!\n",argv[1]);
return -1;
}
databuf[0] = atoi(argv[2]);
ret = write(fd,databuf,sizeof(databuf));
if(ret <0){
printf("beep control failed!!\n");
close(fd);
return -1;
}
ret = close(fd);
if(ret<0){
printf("file %s close failed!!\n",argv[1]);
return -1;
}
return 0;
}
加载驱动:insmod misc_drv.ko
运行:
开 ./misc_app /dev/miscbeep 1
关 ./misc_app /dev/miscbeep 0