1、MISC简介
MISC驱动也称为杂项驱动,是一种简单的字符设备驱动。当某些外设无法进行分类的时候就会使用MISC驱动,其通常嵌套在platform总线驱动中,实现复杂的驱动。
其中MISC设备的主设备号是固定为10,而子设备号可以自动分配(设置255时)
或者自定义。并且它会自动创建cdev字符设备。
2、以前普通的字符设备驱动和MISC字符设备驱动
传统的创建设备和注销设备
/* 传统的创建设备过程 */
1 alloc_chrdev_region(); /* 申请设备号 */
2 cdev_init(); /* 初始化 cdev */
3 cdev_add(); /* 添加 cdev */
4 class_create(); /* 创建类 */
5 device_create(); /* 创建设备 */
/* 传统的删除设备的过程 */
1 cdev_del(); /* 删除 cdev */
2 unregister_chrdev_region(); /* 注销设备号 */
3 device_destroy(); /* 删除设备 */
4 class_destroy(); /* 删除类 */
现在MISC创建设备和注销设备
int misc_register(struct miscdevice * misc);
int misc_deregister(struct miscdevice *misc);
3、驱动程序
/*
* 根据linux内核的程序查找所使用函数的对应头文件。
*/
#include <linux/module.h> //MODULE_LICENSE,MODULE_AUTHOR
#include <linux/init.h> //module_init,module_exit
#include <linux/kernel.h> //printk
#include <linux/fs.h> //struct file_operations
#include <linux/slab.h> //kmalloc, kfree
#include <linux/uaccess.h> //copy_to_user,copy_from_user
#include <linux/io.h> //ioremap,iounmap
#include <linux/cdev.h> //struct cdev,cdev_init,cdev_add,cdev_del
#include <linux/device.h> //class
#include <linux/of.h> //of_find_node_by_path
#include <linux/of_gpio.h> //of_get_named_gpio
#include <linux/gpio.h> //gpio_request,gpio_direction_output,gpio_set_value
#include <linux/atomic.h> //atomic_t
#include <linux/of_irq.h> //irq_of_parse_and_map
#include <linux/interrupt.h> //request_irq
#include <linux/timer.h> //timer_list
#include <linux/jiffies.h> //jiffies
#include <linux/atomic.h> //atomic_set
#include <linux/signal.h> //相关的驱动程序上发给应用程序的信号
#include <linux/platform_device.h> //platform_device_register,platform_device_unregister
#include <linux/device.h> //platform_device
#include <linux/ioport.h> //resource
#include <linux/miscdevice.h> //misc
#define MISCLED_NAME "miscled" /* 设备名称 */
#define MISCLED_MINOR 144 /* 子设备号 */
#define ON 1 /* 打开 */
#define OFF 0 /* 关闭 */
/*=========================================================================================*/
/********************** 3、设备结构体 *************************/
struct miscled_dev {
struct device_node *nd; /* 设备节点 */
int miscled_gpio; /* led所使用的GPIO编号 */
};
struct miscled_dev miscled; /* 定义miscled设备 */
/************************************************************/
/*=========================================================================================*/
/*************************************** 4.1、字符设备文件操作函数 ***************************************/
static int miscled_open(struct inode *inde, struct file *filp) {
/* 设置私有类属性 */
filp->private_data = &miscled;
return 0;
}
static int miscled_close(struct inode *inde, struct file *filp) {
return 0;
}
static ssize_t miscled_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) {
return 0;
}
static ssize_t miscled_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) {
int ret;
u8 receiverbuf[1];
/* 提取私有类属性 */
struct miscled_dev *dev = (struct miscled_dev*)filp->private_data;
ret = copy_from_user(receiverbuf,buf,count);
if(ret < 0) {
printk("user write kernel failed!\r\n");
return -EFAULT; //返回错误地值标志
}
if(receiverbuf[0] == ON) {
gpio_set_value(miscled.miscled_gpio,0); //打开LED灯
} else if(receiverbuf[0] == OFF) {
gpio_set_value(miscled.miscled_gpio,1); //关闭LED灯
}
return 0;
}
/********************************************************************************************************/
/*=========================================================================================*/
/************************* 4、操作集 *************************/
static struct file_operations miscled_fops = {
.owner = THIS_MODULE,
.open = miscled_open,
.release = miscled_close,
.read = miscled_read,
.write = miscled_write,
};
/************************************************************/
static struct miscdevice miscled_miscdev = {
.minor = MISCLED_MINOR,
.name = MISCLED_NAME,
.fops = &miscled_fops,
};
/*=========================================================================================*/
/***************** 2.1、platform平台出入口函数 ******************/
static int miscled_probe(struct platform_device *dev) {
int ret = 0;
printk("miscled probe\r\n");
/************** 5、初始化LED所使用的GPIO *************/
miscled.nd = dev->dev.of_node; //获取设备节点
if(miscled.nd == NULL) {
printk("gpioled node find!\r\n");
return -EINVAL; /* 返回无效参数 */
}
miscled.miscled_gpio = of_get_named_gpio(miscled.nd,"led-gpio",0); //获取设备树中的GPIO属性,得到对应的GPIO编号
if(miscled.miscled_gpio < 0) {
printk("can't get led-gpio!\r\n");
return -EINVAL; /* 返回无效参数 */
}
ret = gpio_direction_output(miscled.miscled_gpio, 0); //设置led对应的GPIO输出模式,并设置默认低电平
if(ret < 0) {
printk("can't set gpio!\r\n");
}
ret = misc_register(&miscled_miscdev);
if(ret < 0) {
printk("misc device register failed!\r\n");
return -EFAULT;
}
printk("minor = %d\r\n",MINOR(miscled_miscdev.minor));
/*******************************************************/
return 0;
}
static int miscled_remove(struct platform_device *dev) {
printk("miscled remove\r\n");
gpio_set_value(miscled.miscled_gpio,1); //关闭LED灯
gpio_free(miscled.miscled_gpio); //释放GPIO
misc_deregister(&miscled_miscdev); //注销misc设备驱动
return 0;
}
/****************************************************************/
/*=========================================================================================*/
/****************** 2、驱动平台platform结构体 **********************/
static const struct of_device_id of_miscled_match[] = {
{.compatible = "alientek,gpioled"},
{},
};
static struct platform_driver miscled_platform_driver = {
.probe = miscled_probe,
.remove = miscled_remove,
.driver = {
.name = "misc-led",
.of_match_table = of_miscled_match,
},
};
/*****************************************************************/
/*=========================================================================================*/
/***************** 1、驱动模块注册与注销及其他信息 ********************/
// static int __init miscled_init(void) {
// return platform_driver_register(&miscled_platform_driver); //注册platform驱动平台
// }
// static void __exit miscled_exit(void) {
// platform_driver_unregister(&miscled_platform_driver); //注销platform驱动平台
// }
// module_init(miscled_init); //注册驱动模块
// module_exit(miscled_exit); //注销驱动模块
module_platform_driver(miscled_platform_driver); //驱动模块注册与注销及其他信息,这个可以直接代替前面的操作
MODULE_LICENSE("GPL"); //驱动许可
MODULE_AUTHOR("DJW"); //个人信息
/********************************************************************/
/*=========================================================================================*/