一、前言

misc驱动也叫杂项驱动,就是某些外设无法进行分类的时候就可以使用MISC驱动。MISC驱动其实就是字符设备驱动,通常嵌套在platform总线驱动中。

二、简介

所有的MISC设备驱动的主设备号都为10,不同的设备使用不同的次设备号。

MISC设备会自动创建cdev,不需要手动创建,因此可以简化字符设备驱动的编写。

2.1、定义MISC设备

linux中用miscdevice表示一个MISC设备,如:

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;
};

定义一个MISC设备后需要设备minor、name、fops三个成员变量。

①、minor:因为主设备号固定为10,所以只需要设置次设备号minor,linux在miscdevice.h中预定义了一些MISC设备的子设备号,可以使用这些预定义的,也可以自定义,只要这个子设备号没被其他设备使用;

②、name:就是此设备的名字,设备注册成功后就会在/dev目录下生成一个名为name的设备文件;

③、fops就是字符设备的操作集合;

2.2、注册设备

设置好miscdevice后就需要使用misc_register函数向系统注册一个MISC设备:

/*
@misc:要注册的MISC设备@return:0,成功<0,失败
*/
int misc_register(struct miscdevice *misc)

这个函数用来代替之前创建设备的方法:

alloc_chrdev_region();     /* 申请设备号 */
cdev_init();               /* 初始化 cdev */
cdev_add();                /* 添加 cdev */
class_create();            /* 创建类 */
device_create();           /* 创建设备 */

2.3、注销设备

卸载驱动的时候,使用misc_deregister函数注销掉MISC设备。

/*
@misc:要注销的MISC设备@return:0,成功<0,失败
*/
int misc_deregister(srtuct miscdevice *misc);

同样,这个函数也代替了之前的一系列删除此前创建的cdev,设备的函数:

cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */

这样确实简化了字符设备驱动编写。

三、驱动编写

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>#define LEDDEV_CNT     1
#define LEDDEV_NAME    "miscbeep"#define  LED_ON      1
#define LED_OFF     0//设备结构体
struct leddev_dev{dev_t devid;struct cdev cdev;struct class *class;struct device *device;int major;int minor;struct device_node *nd;        //设备节点int led_gpio;             //led所使用的GPIO编号struct miscdevice misc;
};struct leddev_dev leddev;  static void led_switch(uint8_t sta)
{if (sta == LED_ON){gpio_set_value(leddev.led_gpio, 0);} else if (sta == LED_OFF) {gpio_set_value(leddev.led_gpio, 1);}
}static int leddev_open(struct inode *inode, struct file *filp)
{filp->private_data = &leddev;printk("leddev open!\n");return 0;
}static ssize_t leddev_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos)
{   printk("leddev read\n");return 0;
}static ssize_t leddev_write(struct file *filp, const char __user *buf, size_t count, loff_t *oppos)
{int ret;uint8_t data_buf[1];ret = copy_from_user(data_buf, buf, count);if (ret < 0){printk("write data fail\n");return -EFAULT;}led_switch(data_buf[0]);return 0;
}static int leddev_release(struct inode *inode, struct file *filp)
{printk("led release\n");return 0;
}static const struct file_operations leddev_fops = {.owner = THIS_MODULE,.open  = leddev_open,.read  = leddev_read,.write = leddev_write,.release = leddev_release,
};/*
*platform驱动的probe函数
*驱动与设备匹配成功以后此函数就会执行
*/static int leddev_probe(struct platform_device *dev)
{int ret = 0;printk("led driver and device has match\r\n");//通过节点名字查找节点leddev.nd = of_find_node_by_name(NULL, "beep");if (leddev.nd == NULL){printk("find %s fail\r\n", "beep");return -EINVAL;}//获取GPIO编号leddev.led_gpio = of_get_named_gpio(leddev.nd, "beep-gpio", 0);if (leddev.led_gpio < 0){printk("get gpio fail\r\n");return -EINVAL;}else{printk("led_gpio value is %d", leddev.led_gpio);}//设置led状态ret = gpio_direction_output(leddev.led_gpio, 1);if (ret < 0){printk("set led status fail\r\n");return -EINVAL;}leddev.misc.minor = 66;leddev.misc.name = LEDDEV_NAME;leddev.misc.fops = &leddev_fops;ret = misc_register(&leddev.misc);if (ret < 0){printk("register miscbeep fail\r\n");return -EINVAL;}return 0;//分配设备号if (leddev.major) {leddev.devid = MKDEV(leddev.major, 0);register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);} else {alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);leddev.major = MAJOR(leddev.devid);leddev.minor = MINOR(leddev.devid);}printk("leddev major=%d, minor= %d\r\n", leddev.major, leddev.minor);//初始化cdevleddev.cdev.owner = THIS_MODULE;cdev_init(&leddev.cdev, &leddev_fops);//添加cdevcdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);//创建类leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);//创建设备leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);return 0;
}static int leddev_remove(struct platform_device *dev)
{led_switch(LED_OFF);misc_deregister(&leddev.misc);
}static const struct of_device_id led_of_match[] = {{ .compatible = "atkmini-beep"},{}
};/*
*platform平台驱动结构体
*/
static struct platform_driver led_driver = {.driver = {.name = "imx6ul-beep",.of_match_table = led_of_match,},.probe = leddev_probe,.remove = leddev_remove,
};static int __init leddriver_init(void)
{return platform_driver_register(&led_driver);
}static void __exit leddriver_exit(void)
{platform_driver_unregister(&led_driver);printk("newchrdev exit\n");
}module_init(leddriver_init);
module_exit(leddriver_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZK");

四、测试

一、linux驱动开发-10.1-MISC驱动相关推荐

  1. Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)

    文章目录 全系列传送门 引言 驱动介绍 Hello World 1. 包含头文件 2. 驱动模块的入口和出口 3. 声明信息 4. 功能实现 完整代码 编译 第一种方法 第二种方法 编译成模块 第一步 ...

  2. Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇

    Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...

  3. Linux驱动开发(外传)---驱动开发调试方法

    前文回顾 <Linux驱动开发(一)-环境搭建与hello world> <Linux驱动开发(二)-驱动与设备的分离设计> <Linux驱动开发(三)-设备树> ...

  4. Linux驱动开发:字符设备驱动开发实战

    Linux驱动开发:字符设备驱动开发实战 一.工程创建 VSCode 创建工程,设置 C/C++ 配置,导入 linux kernel 源码目录,方便 vscode 写代码自动补全,vscode 配置 ...

  5. Linux下驱动开发_块设备驱动开发(硬件上采用SD卡+SPI协议)

    一.前言 块设备主要为存储设备设计的框架. 在前面章节Linux下驱动开发_块设备驱动开发(内存模拟存储) 里介绍了块设备驱动编写思路,并且利用内存模拟了硬件存储,完成了块设备驱动开发测试.这一篇文章 ...

  6. STM32MP157驱动开发——多点电容触摸屏驱动

    STM32MP157驱动开发--多点电容触摸屏驱动 一.简介 二.电容触摸屏驱动框架简介 多点触摸(MT)协议详解 三.驱动开发 1.添加 FT5426 设备节点 2.FT5426 节点配置 3.驱动 ...

  7. i.MX 6ULL 驱动开发 六:beep 驱动

    一.原理分析 通过原理图可以确定 beep 连接到 SNVS_TAMPER1 引脚上.根据 beep 原理,当 SNVS_TAMPER1 输出低电平时,beep 鸣叫. 通过数据手册确定 SNVS_T ...

  8. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之驱动设计的思想:面向对象/分层/分离

    文章目录 前言 1.分离设计 驱动程序分析---程序分层 通用驱动程序---面向对象 个性化驱动程序---分离 APP 程序分析 前言 韦东山嵌入式Linux驱动开发基础知识学习笔记 文章中大多内容来 ...

  9. Linux驱动开发:platform总线驱动

    目录 1.为什么需要platform总线 2.设备端:platform_device 2.1 platform_device结构体 2.2 注册 2.3 注销 3.驱动端:platform_drive ...

最新文章

  1. 三维重建的核心模块有哪些?
  2. [WS]使用Axis发布简单的Web服务
  3. python时间序列因果检验_Python Statsmodels的时间序列Ljung_Box检验
  4. python怎么读文件名-python如何获取当前文件夹下所有文件名详解
  5. 机器学习/深度学习 问题总结及解答
  6. PAT1098【插入排序+堆排序】
  7. WannaCry警示:学会检测和减轻云端恶意内容
  8. 周志华教授专著《集成学习:基础与算法》上市,豆瓣满分森林书破解AI实践难题...
  9. Android Studio 2.2 HTTP proxy setting 提示异常
  10. 如何搜索旅行的好地方(MongoDb LINQ和.NET Core)
  11. 计算机网络第五版谢希仁答案
  12. C语言short转成int,short转换int的小例子
  13. uci2019计算机录取,美国加州大学这九所分校2019最新录取数据
  14. 网吧服务器哪个好稳定,网吧服务器不应盲目追高新:够用稳定就好
  15. 梁定郊:一个人行贿赠西藏、新疆狂 野之旅
  16. first DG方法:二维ODE的边值问题
  17. 麒麟服务器v10系统安装时报错,银河麒麟V10服务器版本编译安装php7.2.12
  18. OpenGL超级宝典(第7版)之第十二章管线监控
  19. 大话SEO网站优化|SEO优化入门技术详解
  20. 土地利用覆被变化的概念_土地利用和覆被变化(LUCC)过程及效应

热门文章

  1. 共谋金融信创发展之路——金融壹账通一行到访麒麟信安进行合作洽谈
  2. Linux 下socket编程 connect()函数返回-1(error:Connection refused)
  3. 蓝桥杯真题 包子凑数 c++代码实现 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 N 种蒸笼,其中第 i种蒸笼恰好能放 Ai个包子。
  4. 外观专利申请流程是怎样的?
  5. php多线程-传入数据到线程中
  6. 提高品牌忠诚度 360email邮件营销三步走
  7. jquery实现点击复制文本
  8. Jetson 系列——基于yolov5对火源或者烟雾的检测,使用tensorrt、c++和int8加速
  9. cf指定服务器菜鸟营,设置服务器只接受Cloudflare的CDN IP连接方法 服务器仅允许CF IP访问的方法...
  10. Qualifier使用