驱动程序开发:MISC杂项驱动

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");   //个人信息
/********************************************************************/
/*=========================================================================================*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓家文007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值