嵌入式Linux 开发经验:注册一个 misc 设备

news2024/11/15 3:54:39

前言

  • 之前买过好几本Linux 设备驱动的书,不过对设备驱动一知半解,什么叫设备,什么又叫驱动?最近工作需要,从源码级别深入的研究了一下 Linux 下的设备与驱动的概念,略有所收获

  • 一般提起驱动开发,都是面向硬件的,至少是底层开发,依赖具体的平台,Linux 作为一个通用的操作系统内核,当前不可能顾及所以的具体外设驱动,只能抽取出驱动的共性,抽象出一个设备驱动模型(框架)出来,这个设备模型从上层看,无论设备多么简单或者复杂,把共性的设备操作,如:注册、反注册、打开、关闭、控制、读写等 封装成 总线、驱动、设备,与设备树配合起来,为上层提供通用的设备操作接口,如文件接口、socket 接口,为底层设备驱动开发提供便利,降低驱动开发的难度。

  • 其实就是抽象与分层,让驱动开发就像是【填空题】,照着模板填空补充,就可以开发具体的设备驱动了。设备驱动的目的,就是驱使设备工作起来,可以让上层应用操作。

测试环境搭建

  • ubuntu 20.04

  • VMware Workstation Pro 16

  • 基于qemu(模拟器),vexpress-a9 平台

  • Linux 6.0.10 (当前最新版本)

  • 注册一个简单的misc 设备,掌握misc 设备注册的方法

misc 设备是什么设备

  • 大家经常提到的是 三大类设备:【字符设备】、【块设备】、【网络设备】。

  • misc 设备是什么呢?为何使用 misc 设备?

  • 如今Linux 设备驱动非常的庞大,所以当前接触的一些外设,都有类似的驱动模型,misc (杂类设备)属于 char 字符设备。

  • 使用 misc 设备的好处就是 Linux 提供了完善的 misc 设备管理,使用 misc 设备提供的API,就可以方便的注册管理 一个 misc 具体设备,使用 misc 设备最核心的 一般是使用 open、close、ioctl 接口,这些接口,可以让用户太的应用操作设备。

  • 注册了一个 misc 设备,如 led0,用户态程序通过 open("/dev/led0", O_RDWR),就可以打开内核驱动misc 设备,通过 ioctl 就可以控制 内核驱动 misc 设备。

  • 也就有一些设备,不是直接读写的,大部分操作都是控制命令,如空调的控制,一般有打开空调、关闭空调、调节空调的温度、模式等操作,可以把空调作为misc 设备来控制,打开关闭使用 open close,调节温度、模式等使用 ioctl。

注册 misc 设备

  • 这里就注意一点: 驱动与设备的概念,这里 misc 属于设备。

  • 这里为了方便,注册一个简单的设备,与上一篇 嵌入式Linux 开发经验:platform_driver_register 的使用方法 平台驱动 配合起来,当 平台驱动匹配设备树节点成功后,再初始化 misc 设备。

  • 新建 linux-6.0.10/drivers/led_control/led_misc.c

#include "led_misc.h"

#define LED_MISC_DEVICE_NAME        "led_misc"

struct led_misc_dev
{
	struct miscdevice misc;
};

struct led_misc_dev *led_miscdev;

/* 打开设备,用户态执行 open 命令,就会走到这里 */
static int led_misc_open(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "%s : enter\n", __func__);
    return 0;
}

/* 打开设备,用户态执行 close 命令,就会走到这里 */
static int led_misc_close(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "%s : enter\n", __func__);
    return 0;
}

/* 内存映射,大部分功能都差不多 */
static int led_misc_mmap(struct file *filp, struct vm_area_struct *vma)
{
    int ret = 0;

    if (filp == NULL)
    {
        printk(KERN_ERR "invalid file!");
        return -EFAULT;
    }
    if (vma == NULL)
    {
        printk(KERN_ERR "invalid vma area");
        return -EFAULT;
    }

    ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
        vma->vm_end - vma->vm_start, vma->vm_page_prot);

    printk(KERN_INFO "%s : ret = %d\n", __func__, ret);

    return ret;
}

/* 设备控制类,用户态执行 ioctl 命令,就会走到这里 */
static long led_misc_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
    printk(KERN_INFO "%s : enter\n", __func__);
    return 0;
}

/* 设备的操作,用户态 应用通过【文件】操作接口操作 */
static const struct file_operations led_misc_fops =
{
    .owner  = THIS_MODULE,
    .llseek = no_llseek,
    .unlocked_ioctl = led_misc_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl = led_misc_ioctl,
#endif
    .mmap = led_misc_mmap,
    .open = led_misc_open,
    .release = led_misc_close,
};

/* 注意这个 初始化不是自动初始化,放在 平台驱动 probe 函数  */
int led_miscdev_init(void)
{
    int ret;

    led_miscdev = kzalloc(sizeof(*led_miscdev), GFP_KERNEL);
    if (!led_miscdev)
        return -ENOMEM;

    led_miscdev->misc.minor = MISC_DYNAMIC_MINOR;
    led_miscdev->misc.fops = &led_misc_fops;
    led_miscdev->misc.name = LED_MISC_DEVICE_NAME;
    led_miscdev->misc.nodename = LED_MISC_DEVICE_NAME;

    ret = misc_register(&led_miscdev->misc);
    if (ret < 0)
    {
        printk(KERN_INFO "%s : error\n", __func__);
    }
    else
    {
        printk(KERN_INFO "%s : ok\n", __func__);
    }

    return ret;
}


/* 可以放在 平台驱动 remove 函数  */
void led_miscdev_exit(void)
{
    misc_deregister(&led_miscdev->misc);
    printk(KERN_INFO "%s : ok\n", __func__);
}
  • 新建 linux-6.0.10/drivers/led_control/led_misc.h
#ifndef __LED_MISC_H__
#define __LED_MISC_H__

#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>

int led_miscdev_init(void);
void led_miscdev_exit(void);

#endif

其他修改

  • 上面是 注册 misc 设备的实现,但是需要调用才能执行,配合 平台驱动, led_miscdev_init 放在 平台驱动的 probe 函数中,led_miscdev_exit 可以放在 平台驱动 remove 函数,也可以放在 平台驱动 module_exit 的执行函数中

  • 修改 linux-6.0.10/drivers/led_control/led_control.c

static int led_control_probe(struct platform_device *pdev)
{
	printk(KERN_INFO "%s : enter\n", __func__);
	led_miscdev_init();  /* 设备树节点匹配后,调用 */
	return 0;
}

static int led_control_remove(struct platform_device *pdev)
{
	printk(KERN_INFO "%s : enter\n", __func__);
	//led_miscdev_exit();  /* 移除设备驱动时,释放 misc 设备  */
	return 0;
}

static void __exit led_control_driver_exit(void)
{
	printk(KERN_INFO "%s : enter\n", __func__);
	led_miscdev_exit();  /* 移除设备驱动时,释放 misc 设备  */
	platform_driver_unregister(&led_control_driver);
}
  • 修改 linux-6.0.10/drivers/led_control/led_control.h,添加 #include "led_misc.h"
#ifndef __LED_CONTROL_H__
#define __LED_CONTROL_H__

#include <linux/of.h>
#include <linux/platform_device.h>

#include "led_misc.h"

#endif
  • 修改 linux-6.0.10/drivers/led_control/Makefile,增加
obj-$(CONFIG_LED_CONTROL) += led_control.o
obj-$(CONFIG_LED_CONTROL) += led_misc.o

编译与运行

  • 编译与 qemu 运行方法参考上篇 嵌入式Linux 开发经验:platform_driver_register 的使用方法 平台驱动的注册中提到的方法

  • 【小技巧】,这里把 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 编译命令 做成一个 shell 脚本

  • vim mk.sh

#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- $1 $2 $3
  • chmod +x mk.sh 增加执行权限

  • 编译时: ./mk.sh -j4 就可以编译了

在这里插入图片描述

  • 更新 zImge Linux 内核编译的产物,开启 qemu 查看注册的 misc 设备

  • 启动 qemu 的信息包括 如下:

led_control_driver_init : enter
led_control_probe : enter
led_miscdev_init : ok

在这里插入图片描述

  • 说明设备树节点匹配后,正确调用了 misc 设备的初始化函数 led_miscdev_init

  • Linux shell 查看 注册的 misc 设备

ls /sys/class/misc/ -la, 可以查看 ,注意在 /sys/class/misc/ 目录下

在这里插入图片描述

  • 注册 misc 设备成功了,接下来可以编写 用户态的应用,通过文件操作接口,如 open close ioctl 来控制这个 内核 misc 设备了

小结

  • 本篇与上一篇 平台驱动配合,记录了一下 平台驱动+ misc 设备的操作流程,部分简单的设备,可以利用Linux 设备驱动框架提供的便利,想填空题一样快速开发构建自己的实际的设备驱动。

  • 使用 Linux 设备种类大概有三种,不过细分, misc 属于 char 字符设备,当前还有各种形形色色的功能不同的设备。 Misc 设备属于比较常用的简单的控制类设备

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

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

相关文章

[附源码]Python计算机毕业设计Django基于Java的图书购物商城

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

visual stduio code 配置高效舒适web生产环境

与webstrom 之前写了一篇webstorm的配置&#xff0c;参考同学的建议&#xff0c;vscode可能使用的人更多&#xff0c;所以配置了一个vs来试用看看。 一直用不习惯的是全文搜索&#xff0c;还是更喜欢webstrom弹窗式的&#xff0c;还可以显示上下文。包括其他的配置&#xff0…

第二证券|小鹏持续萎靡,理想蔚来逆势反弹破月销记录

12月1日&#xff0c;多家造车新势力先后公布11月销量数据。跟着“银十”出售旺季热度淡去&#xff0c;新势力品牌销量也受轿车零售商场逐渐冷却影响出现整体下滑。接连稳居榜首的埃安、哪吒等品牌均出现4位数以上环比销量下滑。上月商场体现低迷的抱负与蔚来则逆势添加&#xf…

TensorFlow之文本分类算法-6

1 前言 2 收集数据 3 探索数据 4 选择模型 5 准备数据 6 模型-构建训练评估 构建输出层 构建n-gram模型 构建序列模型 GloVe&#xff08;英文全称是Global Vectors for Word Representation&#xff09;是一个全球化的英语语境的单词表示的向量集&#xff0c;其使用非…

新变化新营销 这些知识点你得 Get!(文末有 PPT 福利首次放送)

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 在刚刚结束的第 7 期火山引擎数智平台 VeDI「增长课堂」上&#xff0c;火山引擎数智平台 VeDI 零售行业解决方案、汽车行业解决方案团队&#xff0c;以及慢慢买平台…

LM2903VQPWRQ1比较器 LM73C0QDDCRQ1传感器的中文资料

1、LM2903-Q1双路差分比较器包含两个独立的电压比较器&#xff0c;这些比较器可在宽电压范围内由单电源供电运行。如果两个电源之间的电压差在2V至36V且VCC比输入共模电压至少高1.5V以上&#xff0c;那么它们也可以由双电源供电运行。电流消耗不受电源电压的影响。可将输出连接…

一文带你深入理解【Java基础】· Java集合(下)

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

Pikachu靶场全关攻略(超详细!)

一、靶场搭建 准备工具 phpstudy**pikachu靶场下载地址&#xff1a;**https://github.com/zhuifengshaonianhanlu/pikachu 搭建过程 将靶场文件夹放到phpstudy的www目录 进入pikach文件夹的inc目录&#xff0c;修改靶场配置文件config.inc.php&#xff0c;设置数据库账号密…

Ubuntu 安装 Zotero, 并导入原有数据库,然后同步账户

文章目录写在前面一、下载 Linux 下的 Zotero二、安装Zotero三、导入自己的数据库三、同步账户参考链接写在前面 发文时间&#xff1a;2022.12.03 自己的系统是Ubuntu20.04.5&#xff0c;Zotero 是 Zotero-6.0.18_linux-x86_64.tar.bz2 一、下载 Linux 下的 Zotero 直接登录…

魔兽世界开服教程——魔兽世界服务器架设全攻略---战网+Ladder排行版

需要用到的软件&#xff1a; 1. WAMP5 v1.7.exe &#xff08;这个是为排行榜提供数据库服务&#xff0c;为Mysql数据库&#xff09; 2.PvPGN-1.8.2-0-Win32-MySQL-5.0.45-BIN.zip PvPGN-1.8.2-0-Win32-SQLite-3.5.1-BIN.zip &#xff08;这三个是战网主文件&#xff09; pvpgn-…

使用dos命令符操作,感光屏绘图,ccd摄像头采集图像,并按程序进行机械加工的计算机

使用dos命令符操作&#xff0c;感光屏绘图&#xff0c;ccd摄像头采集图像&#xff0c;并按程序进行机械加工的计算机 使用dos命令符操作&#xff0c;感光屏绘图&#xff0c;ccd摄像头采集图像&#xff0c;并按程序进行机械加工的计算机是一种可以按照dos命令符复制磁带程序&…

yolov1算法思想流程简单讲解概述————(究极简单的讲述和理解)

在我想学习算法的时候&#xff0c;我看某些大佬特别喜欢上来就讲论文&#xff0c;给我搞的贼难受&#xff0c;毕竟本人太辣鸡了&#xff0c;上来这么搞看不懂&#xff0c;经过诸多算法的这样折磨。我打算根据自己的亲身经历和学习过程中遇到的问题出一期&#xff0c;先讲算法整…

智能优化算法(源码)—蜣螂优化算法(Dung beetle optimizer,DBO)

获取更多资讯&#xff0c;赶快关注上面的公众号吧&#xff01; 文章目录启发数学模型滚球跳舞繁殖觅食偷窃伪代码2022年11月27日&#xff0c;东华大学沈波教授团队&#xff0c;继麻雀搜索算法之后&#xff0c;又提出了一种全新的群体智能优化算法——蜣螂优化&#xff08;Dung …

功率信号源在超声波及智能骨料损伤监测中的应用

实验名称&#xff1a;超声波及智能骨料损伤监测原理 研究方向&#xff1a;无损检测、损伤定位 实验原理&#xff1a;换能器所产生的高频信号在介质中传播遇到裂缝、空洞等缺陷产生反射、折射、绕射等现象到达接收端时大量衰减&#xff0c;声学参量发生一定的变化&#xff0c;基…

ABAP学习笔记之——第七章:ABAP数据字典

一、数据字典 在 ABAP 程序里使用的所有对象 (表、视图、结构体、类型等)统称为 ABAP 数据字典。这些对象的信息叫 Metadata 或者 Data Definition&#xff0c;另外&#xff0c;ABAP 数据字典有定义和管理数据结构&#xff0c;集中管理系统中使用的对象的功能。 数据字典类型&…

Spring框架(五):SpringAop底层原理和注解配置

SpringAop底层原理和注解配置引子Aop简介利用Aop原理实现一个Demo&#xff08;代理模式&#xff09;Aop的xml方式实现Aop的注解方式实现总结引子 痛定思痛&#xff0c;主要问题出现在自己雀氏不熟悉框架底层、一些面试题&#xff0c;以及sql的一些情况淡忘了。 本章节的开始是…

[附源码]计算机毕业设计学生疫情防控信息填报系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【信号去噪】基于变分贝叶斯卡尔曼滤波器实现信号滤波附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

安卓APP源码和设计报告——智能垃圾桶

课程名称&#xff1a; 移动互联网应用开发 实验名称&#xff1a; 姓名/学号&#xff1a; 专业/班级&#xff1a; 指导教师&#xff1a; 实验时间&#xff1a; 一、案例功能需求 该系统是了解垃圾分类以及物品查询属于哪类垃圾的智能化APP。该系统可以实现用户登陆注册&a…

[附源码]计算机毕业设计JAVA校园摄影爱好者交流网站

[附源码]计算机毕业设计JAVA校园摄影爱好者交流网站 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM …