一、linux驱动开发-10.1-MISC驱动
一、前言
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驱动相关推荐
- Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)
文章目录 全系列传送门 引言 驱动介绍 Hello World 1. 包含头文件 2. 驱动模块的入口和出口 3. 声明信息 4. 功能实现 完整代码 编译 第一种方法 第二种方法 编译成模块 第一步 ...
- Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇
Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...
- Linux驱动开发(外传)---驱动开发调试方法
前文回顾 <Linux驱动开发(一)-环境搭建与hello world> <Linux驱动开发(二)-驱动与设备的分离设计> <Linux驱动开发(三)-设备树> ...
- Linux驱动开发:字符设备驱动开发实战
Linux驱动开发:字符设备驱动开发实战 一.工程创建 VSCode 创建工程,设置 C/C++ 配置,导入 linux kernel 源码目录,方便 vscode 写代码自动补全,vscode 配置 ...
- Linux下驱动开发_块设备驱动开发(硬件上采用SD卡+SPI协议)
一.前言 块设备主要为存储设备设计的框架. 在前面章节Linux下驱动开发_块设备驱动开发(内存模拟存储) 里介绍了块设备驱动编写思路,并且利用内存模拟了硬件存储,完成了块设备驱动开发测试.这一篇文章 ...
- STM32MP157驱动开发——多点电容触摸屏驱动
STM32MP157驱动开发--多点电容触摸屏驱动 一.简介 二.电容触摸屏驱动框架简介 多点触摸(MT)协议详解 三.驱动开发 1.添加 FT5426 设备节点 2.FT5426 节点配置 3.驱动 ...
- i.MX 6ULL 驱动开发 六:beep 驱动
一.原理分析 通过原理图可以确定 beep 连接到 SNVS_TAMPER1 引脚上.根据 beep 原理,当 SNVS_TAMPER1 输出低电平时,beep 鸣叫. 通过数据手册确定 SNVS_T ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之驱动设计的思想:面向对象/分层/分离
文章目录 前言 1.分离设计 驱动程序分析---程序分层 通用驱动程序---面向对象 个性化驱动程序---分离 APP 程序分析 前言 韦东山嵌入式Linux驱动开发基础知识学习笔记 文章中大多内容来 ...
- Linux驱动开发:platform总线驱动
目录 1.为什么需要platform总线 2.设备端:platform_device 2.1 platform_device结构体 2.2 注册 2.3 注销 3.驱动端:platform_drive ...
最新文章
- 三维重建的核心模块有哪些?
- [WS]使用Axis发布简单的Web服务
- python时间序列因果检验_Python Statsmodels的时间序列Ljung_Box检验
- python怎么读文件名-python如何获取当前文件夹下所有文件名详解
- 机器学习/深度学习 问题总结及解答
- PAT1098【插入排序+堆排序】
- WannaCry警示:学会检测和减轻云端恶意内容
- 周志华教授专著《集成学习:基础与算法》上市,豆瓣满分森林书破解AI实践难题...
- Android Studio 2.2 HTTP proxy setting 提示异常
- 如何搜索旅行的好地方(MongoDb LINQ和.NET Core)
- 计算机网络第五版谢希仁答案
- C语言short转成int,short转换int的小例子
- uci2019计算机录取,美国加州大学这九所分校2019最新录取数据
- 网吧服务器哪个好稳定,网吧服务器不应盲目追高新:够用稳定就好
- 梁定郊:一个人行贿赠西藏、新疆狂 野之旅
- first DG方法:二维ODE的边值问题
- 麒麟服务器v10系统安装时报错,银河麒麟V10服务器版本编译安装php7.2.12
- OpenGL超级宝典(第7版)之第十二章管线监控
- 大话SEO网站优化|SEO优化入门技术详解
- 土地利用覆被变化的概念_土地利用和覆被变化(LUCC)过程及效应
热门文章
- 共谋金融信创发展之路——金融壹账通一行到访麒麟信安进行合作洽谈
- Linux 下socket编程 connect()函数返回-1(error:Connection refused)
- 蓝桥杯真题 包子凑数 c++代码实现 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 N 种蒸笼,其中第 i种蒸笼恰好能放 Ai个包子。
- 外观专利申请流程是怎样的?
- php多线程-传入数据到线程中
- 提高品牌忠诚度 360email邮件营销三步走
- jquery实现点击复制文本
- Jetson 系列——基于yolov5对火源或者烟雾的检测,使用tensorrt、c++和int8加速
- cf指定服务器菜鸟营,设置服务器只接受Cloudflare的CDN IP连接方法 服务器仅允许CF IP访问的方法...
- Qualifier使用