(Linux驱动学习 - 10).MISC驱动实验

一.MISC介绍

1.MISC定义

misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动 ,也就是当我们板子上的某

外设无法进行分类的时候就可以使用 MISC 驱动 。 MISC 驱动其实就是最简单的字符设备驱
,通常嵌套在 platform 总线驱动中,实现复杂的驱动,本章我们就来学习一下 MISC 驱动的

编写。

2.MISC特性

①.所有的 MISC 设备驱动的**主设备号都为 10,**不同的设备使用不同的从设备号。

②.MISC 设备驱动会自动创建 cdev ,因此 MISC 设备驱动编写可以简化字符设备驱动的编写。

二.MISC 设备驱动相关结构体与函数

1.miscdevice 结构体

cpp 复制代码
struct miscdevice 
{
    int minor;                          /* 子设备号 */
    const char *name;                   /* 设备名字 */
    const struct file_operations *fops; /* 设备操作集 */
    struct list_head list;
    struct device *parent;
    struct device *this_device;
    const struct attribute_group **groups;
    const char *nodename;
    umode_t mode;
};

2.注册一个 MISC 设备 - misc_register

函数原型

cpp 复制代码
/**
 * @description:            向系统注册一个 MISC 设备
 * @param - misc    :       要注册的 MISC 设备
 * @return          :       0成功,其他失败
 */
int misc_register(struct miscdevice *misc)

3.注销 MISC 设备 - misc_deregister

cpp 复制代码
/**
 * @description:        注销 MISC 设备
 * @param - misc    :   要注销的 MISC 设备
 * @return          :   0成功,其他失败
 */
int misc_deregister(struct miscdevice *misc)

三.使用 platform 加 MISC 驱动框架编写 beep 蜂鸣器驱动

1.设备树部分

(1).流程图

(2).设备树代码

在 iomuxc 下添加pinctl

在根节点下添加 beep 节点

2.驱动部分

(1).流程图

(2).代码部分

cpp 复制代码
#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 <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>



#define MISCBEEP_NAME   "miscbeep"          /* 名字 */
#define MISCBEEP_MINOR  144                 /* 子设备号 */
#define BEEPOFF         0                   /* 关闭 */
#define BEEPON          1                   /* 打开 */


/* miscbeep 设备结构体 */
struct miscbeep_dev
{
    dev_t   devid;                  /* 设备号 */
    struct cdev cdev;               /* cedv */
    struct class *class;            /* 类 */
    struct device *device;          /* 设备 */
    struct device_node *nd;         /* 设备结点 */
    int beep_gpio;                  /* beep 所使用的 GPIO 编号 */
};

struct miscbeep_dev miscbeep;       //beep 设备


/**
 * @description:            打开设备
 * @param - inode   :       传递给驱动的 inode
 * @param - filp    :       要打开的设备文件
 * @return          :       0成功,其他失败
 */
static int miscbeep_open(struct inode *inode,struct file *filp)
{
    /* 设置私有数据 */
    filp->private_data = &miscbeep; 

    return 0;
}


/**
 * @description:            向设备写数据
 * @param - filp    :       要打开的设备文件
 * @param - buf     :       要写入的数据
 * @param - cnt     :       要写入的字节数
 * @param - offt    :       相对于文件首地址的偏移量
 * @return          :       成功则返回(成功写入的字节数),失败则返回(负数)
 */
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 beep_state;

    struct miscbeep_dev *dev = filp->private_data;

    retvalue = copy_from_user(databuf,buf,cnt);
    if(0 > retvalue)
    {
        printk("kernel write failed!\r\n");
        return -EFAULT;
    }

    beep_state = databuf[0];
    if(BEEPON == beep_state)
    {
        gpio_set_value(dev->beep_gpio,1);       //打开蜂鸣器
    }
    else if(BEEPOFF == beep_state)
    {
        gpio_set_value(dev->beep_gpio,0);       //关闭蜂鸣器
    }

    return 0;
}



/* 设备操作函数 */
static struct file_operations miscbeep_fops = 
{
    .owner = THIS_MODULE,
    .open = miscbeep_open,
    .write = miscbeep_write,
};



/* MISC 设备结构体 */
static struct miscdevice beep_miscdev = 
{
    .minor = MISCBEEP_MINOR,
    .name = MISCBEEP_NAME,
    .fops = &miscbeep_fops,
};




/**
 * @description:            platform 驱动的 probe 函数,当驱动与设备匹配以后会执行此函数
 * @param - dev     :       platform 设备
 * @return          :       0成功,其他失败
 */
static int miscbeep_probe(struct platform_device *dev)
{
    int ret = 0;

    printk("beep driver and device wa matched!\r\n");

    /* 一.初始化 BEEP 要使用的 GPIO */

    /* 1.获取设备结点 */
    miscbeep.nd = of_find_node_by_path("/beep");
    if(NULL == miscbeep.nd)
    {
        printk("beep node not find!\r\n");
        return -EINVAL;
    }

    /* 2.获取 BEEP 的 GPIO 编号 */
    miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd,"beep-gpio",0);
    if(0 > miscbeep.beep_gpio)
    {
        printk("can not get beep-gpio!\r\n");
        return -EINVAL;
    }

    /* 3.申请 gpio */
    gpio_request(miscbeep.beep_gpio,"beep");

    /* 4.初始化 gpio 为 高电平,即初始化关闭 BEEP */
    ret = gpio_direction_output(miscbeep.beep_gpio,1);
    if(0 > ret)
    {
        printk("can not set gpio!\r\n");
    }


    /* 二.注册 MISC 设备驱动 */
    ret = misc_register(&beep_miscdev);
    if(0 > ret)
    {
        printk("misc devie register failed!\r\n");
        return -EFAULT;
    }

    return 0;
}



/**
 * @description:            remove 函数
 * @param - dev     :       platform 设备
 * @return          :       0成功,其他失败
 */
static int miscbeep_remove(struct platform_device *dev)
{
    /* 关闭 BEEP */
    gpio_set_value(miscbeep.beep_gpio,1);

    /* 释放 BEEP 的 GPIO */
    gpio_free(miscbeep.beep_gpio);

    /* 注销 misc 设备驱动 */
    misc_deregister(&beep_miscdev);

    return 0;
}




/* 匹配列表 */
static const struct of_device_id beep_of_match[] = 
{
    {.compatible = "atkalpha-beep"},        //必须与设备树中属性匹配
    {}
};


/* platform 驱动结构体 */
static struct platform_driver beep_driver = 
{
    .driver = 
    {
        .name = "imx6ul-beep",              //驱动名字
        .of_match_table = beep_of_match,    //匹配列表
    },
    .probe = miscbeep_probe,
    .remove = miscbeep_remove,
};





/**
 * @description:            驱动入口函数
 * @param -         :       无
 * @return          :       无
 */
static int __init miscbeep_init(void)
{
    return platform_driver_register(&beep_driver);
}


/**
 * @description:            驱动出口函数
 */
static void __exit miscbeep_exit(void)
{
    return platform_driver_unregister(&beep_driver);
}


module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kaneki");
相关推荐
HLC++8 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室9 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy11 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕12 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫13 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生14 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1115 小时前
linux基础IO
linux·运维·服务器
BelongPanda17 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯17 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983417 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器