Linux MISC 驱动实验

news2024/9/25 10:33:37

目录

一、MISC 设备驱动简介

misc_deregister 函数

二、MISC驱动编写

 1、编写框架

2、platform结构体对应的函数 

2、宏定义和miscbeep设备结构体

3、定义miscdevice结构体

字符设备操作集

4、probe函数

5、remove函数​编辑

 验证

6、添加开关

三、总代码

APP

miscbeep.c

验证


        misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动,也就是当我们板子上的某
些外设无法进行分类的时候就可以使用 MISC 驱动。

一、MISC 设备驱动简介

        所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。随着 Linux字符设备驱动的不断增加,设备号变得越来越紧张,尤其是主设备号, MISC 设备驱动就用于解决此问题。 MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。

需要先向 Linux 注册一个 miscdevice 设备, miscdevice是一个结构体,定义在文件 include/linux/miscdevice.h 中,内容如下:

 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 设备(miscdevice 类型)以后我们需要设置 minor、 name 和 fops 这三个成员变量。 minor 表示子设备号, MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备
号, Linux 系统已经预定义了一些 MISC 设备的子设备号,这些预定义的子设备号定义在
include/linux/miscdevice.h 文件中,在使用的时候可以从这些预定义的子设备号中挑选一个,当然也可以自己定义,只要这个子设备号没有被其他设备使用接口

        name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。 fops 就是字符设备操作集合, MISC 设备驱动最终是需要使用用户提供的 fops操作集合

misc_deregister 函数

        以前我们需要自己调用一堆的函数去创建和卸载设备,比如在以前的字符设备驱动中我们会使用如下几个函数完成设备创建和卸载过程:

创建

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_deregister 函数即可完成上面的操作,设置好 miscdevice结构体 以后就需要使用 misc_register 函数向系统中注册一个 MISC 设备,此函数原型如下:

int misc_register(struct miscdevice * misc)
misc:要注册的 MISC 设备。返回值: 负数,失败; 0,成功

 卸载设备驱动模块的时候需要调用 misc_deregister 函数来注销掉 MISC 设备,函数原型如下:

int misc_deregister(struct miscdevice *misc)
misc:要注销的 MISC 设备。返回值: 负数,失败; 0,成功。

下面开始编写

二、MISC驱动编写

在“蜂鸣器驱动”实验中已经创建好了设备树节点,可以直接使用

 创建文件miscbeep.c文件和APP,修改makefile

添加头文件 #include <linux/miscdevice.h>

 1、编写框架

45行,因为这里使用设备树,所以.name字段无需作匹配功能 ,如果不使用设备树,就要在编写设备的时候保证设备和驱动的name字段要一致

2、platform结构体对应的函数 

39行,compatible字段的值一定要与使用的设备树节点compatible值的要一致

2、宏定义和miscbeep设备结构体

 29行,设置次设备号为144

  

3、定义miscdevice结构体

 65行,次设备号,使用宏定义

66行,设备名字,使用宏定义

67行,字符设备操作集,对应的函数需要实现

字符设备操作集

4、probe函数

 75行,因为已经使用设备树匹配设备节点,所以不需要再通过路径进行搜索,直接利用

dev->dev.of_node 即可获取

76行,获取设备树中的gpio属性,得到BEEP所使用的BEEP编号

81行,申请一个 GPIO 管脚,gpio 设置名字为beep-gpio

88行,设置GPIO5_IO01为输出,并且输出高电平,默认关闭BEEP 

94行, 一般情况下会注册对应的字符设备,但是这里我们使用MISC设备, 所以我们不需要自己注册字符设备驱动,只需要注册misc设备驱动即可

5、remove函数

 退出的时候要把资源释放

 验证

编译后把模块加载到开发板,如下

  可以看到,主设备号为10,次设备号为57(设置的自动分配)

6、添加开关

 添加开关宏定义,在miscbeep_write函数里面获取APP传来的数据,然后根据数据去开关beep

三、总代码

APP

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

/*
    argc:应用程序参数个数(argv数组元素个数)
    argv:具体参数,也可以写作char **argv
    ./miscbeepAPP <filename> <0:1>   0表示关,1表示开
    ./miscbeepAPP  /dev/miscbeep 0    关
    ./miscbeepAPP  /dev/miscbeep 1    开
*/
int main(int argc, char *argv[])
{
    int fd,retvalue;
    char *filename;
    unsigned char databuf[1];

    /*判断命令行输入参数是否正确*/
    if(argc != 3){
        printf("error usage!\r\n");
        return -1;
    }
    /*用指针指向文件*/
    filename = argv[1];
    /*打开文件*/
    fd = open(filename , O_RDWR);
    if(fd < 0){
        printf("file open failed\r\n",filename);
        return -1;
    }
    /*获取控制开关的数字*/
    databuf[0] = atoi(argv[2]);/*将字符转换为数字*/
    /*如果输入的控制命令不是1或者0直接退出*/
    if(((int)databuf[0]) < 0 || ((int)databuf[0]) >1)
    {
        printf("control parameter error\r\n");
        close(fd);
        return -1;
    }
    /*写入操作*/
    retvalue = write(fd,databuf,sizeof(databuf));
    if(retvalue < 0){
        printf("LED control failed\r\n");
        close(fd);
        return -1;
    }
    /*关闭文件*/
    close(fd);

    return 0;
}

miscbeep.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/ide.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>

#define MISCBEEP_NAME   "miscbeep"
#define MISCBEEP_MINOR  144

#define BEEP_OFF 0
#define BEEP_ON  1


/*miscbeep设备结构体*/
struct miscbeep_dev{
    struct device_node *nd;/*设备节点*/
    int beep_gpio;/* beep所使用的GPIO编号*/
};
struct miscbeep_dev miscbeep;/* beep设备 */

static int miscbeep_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &miscbeep;/* 设置私有数据 */
    return 0;
}
static ssize_t miscbeep_write(struct file *filp, const char __user *buf,
			                    size_t count, loff_t *ppos)
{
    int ret = 0;
    unsigned char databuf[1];
    struct miscbeep_dev *dev = filp->private_data;
    ret = copy_from_user(databuf,buf,count);
    if(ret < 0){
        return -EINVAL;
    }
    if(databuf[0] == BEEP_ON){
        gpio_set_value(dev->beep_gpio, 0);/*打开*/
    }else if(databuf[0] == BEEP_OFF){
        gpio_set_value(dev->beep_gpio,1);/*关闭*/
    }
    return 0;
}
static int miscbeep_release(struct inode *inode, struct file *filp)
{
    return 0;
}

/*字符设备操作集*/
struct file_operations miscbeep_fops = {
    .owner  =   THIS_MODULE, 
    .open   =   miscbeep_open,
    .write  =   miscbeep_write,
    .release=   miscbeep_release,
};

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

/*probe函数*/
static int miscbeep_probe(struct platform_device *dev)
{
    int ret =0;
    /*1、初始化beep的io*/
    miscbeep.nd = dev->dev.of_node;
    miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd,"beep-gpios",0);
    if(miscbeep.beep_gpio < 0){
        ret = -EINVAL;
        goto fail_findgpio;
    }
    ret = gpio_request(miscbeep.beep_gpio,"beep-gpio");
    if(ret){
        printk("can't request %d gpio\r\n",miscbeep.beep_gpio);
        ret = -EINVAL;
        goto fail_findgpio;
    }
    /*输出默认为高电平*/
    ret = gpio_direction_output(miscbeep.beep_gpio,1);
    if(ret < 0){
        ret = -EINVAL;
        goto fail_setoutput;
    }
    /*2、misc驱动注册*/
    ret = misc_register(&beep_miscdev);
    if(ret < 0){
        ret = -EINVAL;
        goto fail_setoutput;
    }
    return 0;   
fail_setoutput:
    gpio_free(miscbeep.beep_gpio);
fail_findgpio:
    return ret;
}
/*remove函数*/
static int miscbeep_remove(struct platform_device *dev)
{
    /* 注销misc设备 */
    misc_deregister(&beep_miscdev);
    /*拉高关闭beep*/
    gpio_set_value(miscbeep.beep_gpio , 1);
    /*释放GPIO*/
    gpio_free(miscbeep.beep_gpio);
    return 0;
}
/*platform匹配表*/
static const struct of_device_id beep_of_math[] = {
    {.compatible = "my,beep"},
    {/* sentinel */},
};
/*platfrom*/
static struct platform_driver miscbeep_driver = {
    .driver = {
        .name = "imx6ull-beep",
        .of_match_table = beep_of_math,/*设备树匹配表*/
    },
    .probe = miscbeep_probe,
    .remove = miscbeep_remove,

};
/*驱动入口函数*/
static int __init miscbeep_init(void)
{
    return platform_driver_register(&miscbeep_driver);
}
/*驱动出口函数*/
static void __exit miscbeep_exit(void)
{
    platform_driver_unregister(&miscbeep_driver);
}


module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

验证

 主设备号为10,次设备为144,发送0就是关,1就是开;开着卸载驱动也会关

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/376507.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL-锁

MySQL-4-锁概述锁的分类全局锁基本语法&#xff1a;特点表级锁介绍分类表锁读锁测试写锁测试写锁测试元数据锁意向锁分类行级锁介绍行锁间隙锁/临键锁概述 锁是计算机协调多个进程或者线程并发访问某一资源的机制&#xff0c;在数据库中&#xff0c;除传统的计算资源&#xff…

PCB第六道主流程之AOI,你都知道吗

衔接上文&#xff0c;继续为朋友们分享普通单双面板的生产工艺流程。 如图&#xff0c;第六道主流程为AOI。 AOI的目的为&#xff1a; 利用光学原理&#xff0c;比对资料&#xff0c;进行检验&#xff0c;并附带相应的维修与报废处理。 其子流程&#xff0c;主要为3个。 【…

面试必刷101 Java题解 -- part 3

part1 – https://blog.csdn.net/qq_41080854/article/details/129204480 part2 – https://blog.csdn.net/qq_41080854/article/details/129224785 面试必刷101 Java题解 -- part 3动规五部曲71、斐波那契数列72、跳台阶73、最小花费爬楼梯74、最长公共子序列(二)75、最长公共…

比特数据结构与算法(第四章_中_续②)堆解决Topk问题(最小的k个数)

TopK问题介绍&#xff1a;在N个数中找出最大/小的前K个 &#xff08;比如在1000个数中找出最大/小的前10个&#xff09;以前的方法&#xff1a;冒泡排序。时间复杂度&#xff1a; O(N^2)现在找最大的k个数的方法&#xff1a;方法1&#xff1a;堆排序降序&#xff0c;前N个就是最…

提高香港数据中心安全性的 5 种方法

在说明如何有效提高香港数据中心安全性之前&#xff0c;让我们快速了解什么是香港数据中心&#xff0c;以及为什么它对任何企业都很重要。 什么是香港数据中心? 无需深入研究复杂的术语和过多的细节&#xff0c;香港数据中心只是负责保存公司大量敏感或专有信息的设施&#xf…

使用gitee搭建图床,并解决防盗链问题

使用gitee搭建图床&#xff0c;并解决防盗链问题 一、搭建图床&#xff08;图床—般是指储存图片的服务器&#xff09; 1、有gitee账号&#xff0c;并搭建一个gitee仓库 点击新建仓库&#xff1a; 填写信息&#xff1a; 新建完就是这个模样了&#xff0c;点击管理&#xff1…

RFID射频卡写入手机NFC心路小记

声明&#xff1a; 本文仅是作者学习探索的心里路程日记&#xff0c;如果您看完以后&#xff0c;从中获得了一些知识&#xff0c;作者不胜荣幸。科技是一把双刃剑&#xff0c;利用好了&#xff0c;可以方便生活&#xff0c;利用不当也肯能扰乱公共管理秩序&#xff0c;造成不必要…

【软件测试】测试老鸟的迷途,进军高级自动化测试测试......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 很多从业几年的选手…

如何在没有任何额外包的情况下使用 NodeJS 下载文件

如何在没有任何额外包的情况下使用 NodeJS 下载文件 您可以下载文件&#xff08;图像、文本或任何类型的文件&#xff09;并使用 NodeJS 内置 https和 fs模块将其保存到您的文件系统。 该 https模块允许您使用 NodeJS 创建 HTTPS 请求&#xff0c;同时该 fs模块授予您访问文件…

VR全景的普及还将会带来什么新的风口?

5G技术的普及让VR全景在诸多行业中逐渐融合应用&#xff0c;VR全景展示可以更加真实、更加直观地让用户自主观看现场真实场景&#xff0c;基于身临其境的效果&#xff0c;VR全景展示已经被广泛的应用于各行各业&#xff0c;那么VR全景的普及还将会带来什么新的风口呢&#xff1…

FAST‘23《λ-IO: A Unified IO Stack for Computational Storage》论文解读

FAST’23《λ-IO: A Unified IO Stack for Computational Storage》论文解读 Data:2023-2-27 Ref: Z. Yang et al., “λ-IO: A Unified IO Stack for Computational Storage,” in 21st USENIX Conference on File and Storage Technologies (FAST 23), Santa Clara, CA, Feb.…

我的Android前沿技术—— Artifactory私服 搭建

我们说的私服&#xff0c;其实指的是企业局域网内的软件包依赖库。 说到软件库&#xff0c;就会牵扯出另一个概念——包管理器。 包管理器是在电脑中自动安装、配置、卸载和升级软件包的工具组合。包管理器由于其便捷性&#xff0c;被越来越多的新技术所采纳&#xff0c;从老…

Cesium 编程入门

Cesium 是什么&#xff1f; Cesium 是一个跨平台、跨浏览器的展示三维地球和地图的Javascript库。 Cesium 使用WebGL 来进行硬件加速图形&#xff0c;使用时不需要任何插件支持&#xff0c;但是浏览器必须支持WebGL。 Cesium能做什么&#xff1f; 支持2D、2.5D、3D形式的地图展…

Java代码规范

前言 由于近年来对于代码质量的要求越来越高&#xff0c;特制定部门级Java代码规范规则集X-JAVA-RULE&#xff0c;整体要求规则可用可查、循序渐进。 可用是指考虑目前已有代码的体量&#xff0c;不满足这些规则的代码能否能被修复&#xff0c;如果工作量巨大不能被修复或者实…

小程序和Vue+uniapp+unicloud培训课件

文章目录**一、什么是小程序****1.1** **小程序简介****1.2** **小程序的特点****1.3** **小程序的开发流程**个人小程序和企业小程序的区别1.4 小程序代码构成1.4.1 JSON 配置1.4.2 WXML 模板**数据绑定**逻辑语法条件逻辑列表渲染模板引用共同属性1.4.3 WXSS 样式1.4.4 JS 逻…

9. IP组播(理论)

作为IP传输三种方式之一&#xff0c;IP组播通信指的是IP报文从一个源发出&#xff0c;被转发到一组特定的接收者。相较于传统的单播和广播&#xff0c;IP组播可以有效地节约网络带宽、降低网络负载&#xff0c;所以被广泛应用于IPTV、实时数据传送和多媒体会议等网络业务中。 …

5 逻辑回归及Python实现

1 主要思想 分类就是分割数据&#xff1a; 两个条件属性&#xff1a;直线&#xff1b;三个条件属性&#xff1a;平面&#xff1b;更多条件属性&#xff1a;超平面。 使用数据&#xff1a; 5.1,3.5,0 4.9,3,0 4.7,3.2,0 4.6,3.1,0 5,3.6,0 5.4,3.9,0 . . . 6.2,2.9,1 5.1,2.5…

一个容易被忽视的标签 —— iframe

前言 甲问&#xff1a;说说你知道的HTML标签。 乙于是说了一大堆标签&#xff0c;比如div&#xff0c;span等等。 甲说&#xff1a;那你知道 iframe 标签吗&#xff1f; 乙这时候迟疑了片刻&#xff0c;缓缓说出&#xff1a;知道它&#xff0c;但是不太了解这个标签。 HTM…

学到了,原来华为是这样判断MES系统的好坏的

可以想象华为公司对供应商的要求是多么严格&#xff0c;那么我们今天来谈一下华为对供应商工厂MES系统这块的要求&#xff0c;这要从生产防错系统、品质管控系统、品质追溯系统、出货防错系统四个方面来说。一、生产物料和生产治具防错系统建立完整的物料和治具标签方案&#x…

常用的数据脱敏(手机、邮箱、身份证号)

一、什么是数据脱敏 先来看看什么是数据脱敏&#xff1f;数据脱敏也叫数据的去隐私化&#xff0c;在我们给定脱敏规则和策略的情况下&#xff0c;对敏感数据比如 手机号、银行卡号 等信息&#xff0c;进行转换或者修改的一种技术手段&#xff0c;防止敏感数据直接在不可靠的环境…