linux 驱动——字符设备驱动(自动生成设备节点文件)

文章目录

    • 字符设备驱动
    • 字符设备 APP
    • 生成 dev 节点的原理
    • 配置内核自动创建设备节点
    • 模块使用

字符设备驱动

#include "linux/device/class.h"
#include "linux/export.h"
#include "linux/uaccess.h"
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>#define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */
#define CHRDEVBASE_NUM 1             /* 设备数目 */static char write_buf[100];
static char read_buf[100];static char *string_test = "kernel data this tyustli test";typedef struct {dev_t dev_id;          /* 设备号 */struct cdev c_dev;     /* cdev */struct class *class;   /* 类 */struct device *device; /* 设备 */int major;             /* 主设备号 */int minor;             /* 次设备号 */
} new_chrdev_t;new_chrdev_t new_chrdev;static int chrdevbase_open(struct inode *inode, struct file *file)
{printk("k: chrdevbase open\r\n");return 0;
}static ssize_t chrdevbase_read(struct file *file, char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;printk("k: chrdevbase read\r\n");memcpy(read_buf, string_test, strlen(string_test));ret = copy_to_user(buf, read_buf, count);if (ret == 0) {printk("k: read data success\r\n");} else {printk("k: read data failed ret = %ld\r\n", ret);}return ret;
}static ssize_t chrdevbase_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)
{unsigned long ret = 0;printk("k: chrdevbase write\r\n");ret = copy_from_user(write_buf, buf, count);if (ret == 0) {printk("k: write data success write data is: %s\r\n", write_buf);} else {printk("k: write data failed ret = %ld\r\n", ret);}return count;
}static int chrdevbase_release(struct inode *inode, struct file *file)
{printk("k: chrdevbase release\r\n");return 0;
}static struct file_operations chrdevbase_fops = {.owner = THIS_MODULE,.open = chrdevbase_open,.read = chrdevbase_read,.write = chrdevbase_write,.release = chrdevbase_release,
};static int __init chrdevbase_init(void)
{int err = 0;err = alloc_chrdev_region(&new_chrdev.dev_id, 0, CHRDEVBASE_NUM,CHRDEVBASE_NAME);if (err < 0) {printk("k: alloc chrdev region failed err = %d\r\n", err);return -1;}/* get major and minor */new_chrdev.major = MAJOR(new_chrdev.dev_id);new_chrdev.minor = MINOR(new_chrdev.dev_id);printk("k: newcheled major=%d,minor=%d\r\n", new_chrdev.major,new_chrdev.minor);new_chrdev.c_dev.owner = THIS_MODULE;cdev_init(&new_chrdev.c_dev, &chrdevbase_fops);err = cdev_add(&new_chrdev.c_dev, new_chrdev.dev_id, CHRDEVBASE_NUM);if (err < 0) {printk("k: cdev add failed err = %d\r\n", err);goto out;}new_chrdev.class = class_create(CHRDEVBASE_NAME);if (IS_ERR(new_chrdev.class)) {printk("k: class create failed\r\n");goto out_cdev;}new_chrdev.device = device_create(new_chrdev.class, NULL, new_chrdev.dev_id,NULL, CHRDEVBASE_NAME);if (IS_ERR(new_chrdev.device)) {printk("k: device create failed\r\n");goto out_class;}printk("k: base module init\r\n");return 0;out_class:class_destroy(new_chrdev.class);
out_cdev:cdev_del(&new_chrdev.c_dev);
out:unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);return err;
}static void __exit chrdevbase_exit(void)
{device_destroy(new_chrdev.class, new_chrdev.dev_id);class_destroy(new_chrdev.class);cdev_del(&new_chrdev.c_dev);unregister_chrdev_region(new_chrdev.dev_id, CHRDEVBASE_NUM);printk("k: base module exit!\r\n");
}module_init(chrdevbase_init);
module_exit(chrdevbase_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("tyustli");
MODULE_INFO(intree, "Y"); /* loading out-of-tree module taints kernel */

字符设备 APP

#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"static char usrdata[] = { "user data!" };int main(int argc, char *argv[])
{int fd, retvalue;char *filename;char readbuf[100], writebuf[100];if (argc != 3) {printf("u: error Usage!\r\n");return -1;}filename = argv[1];/* 打开驱动文件 */fd = open(filename, O_RDWR);if (fd < 0) {printf("u: can't open file %s\r\n", filename);return -1;}/* 从驱动文件读取数据 */if (atoi(argv[2]) == 1) {retvalue = read(fd, readbuf, 50);if (retvalue < 0) {printf("u: read file %s failed!\r\n", filename);} else {/*  读取成功,打印出读取成功的数据 */printf("u: read data:%s\r\n", readbuf);}}/* 向设备驱动写数据 */if (atoi(argv[2]) == 2) {memcpy(writebuf, usrdata, sizeof(usrdata));retvalue = write(fd, writebuf, 50);if (retvalue < 0) {printf("u: write file %s failed!\r\n", filename);}}/* 关闭设备 */retvalue = close(fd);if (retvalue < 0) {printf("u: can't close file %s\r\n", filename);return -1;}return 0;
}

生成 dev 节点的原理

dev 目录下的节点不是由驱动本身生成的,是由文件系统中的工具 mdev 生成的;

当系统启动后,加载完内核再去加载文件系统,执行文件系统中的脚本,脚本会执行 mdev -s 命令(即执行 mdev程序),该命令会去遍历/sys/class下的所有文件,寻找所有名为 dev的文件,dev文件保存了每个驱动的主设备号、次设备号,以及驱动名。

生成设备节点的依赖有两个

  • /sys/class 有驱动的节点信息,即 dev 文件
  • 执行 mdev -s创建 /dev 下的节点
ls /sys/class

在这里插入图片描述
这里文件是有的,这个时候执行

mdev -s

并查看 /dev/ 目录

ls /dev

在这里插入图片描述
可以看到设备节点文件自动创建了

配置内核自动创建设备节点

配置 linux 内核使之自动创建设备节点文件
在这里插入图片描述
在内核中 make menuconfig 使能 CONFIG_UEVENT_HELPER

在这里插入图片描述

模块使用

linux 自动创建设备节点之后,就不用手动创建了,可以直接查看 /dev 目录下已经生成了设备节点文件

ls /dev

模块安装

modprobe my_module

模块使用

lib/modules/6.5.7+/my_app /dev/chrdevbase 1

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mapbox使用marker创建html点位信息

mapbox使用marker创建html点位信息 codePen地址 mapboxgl.accessToken "pk.eyJ1IjoibGl1emhhbzI1ODAiLCJhIjoiY2xmcnV5c2NtMDd4eDNvbmxsbHEwYTMwbCJ9.T0QCxGEJsLWC9ncE1B1rRw"; const center [121.29786, 31.19365]; const map new mapboxgl.Map({container: &quo…

解析mfc100u.dll文件丢失的修复方法,快速解决mfc100u.dll问题

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是“缺少某个文件”的错误。最近&#xff0c;我也遇到了一个这样的问题&#xff0c;那就是“mfc100u.dll丢失”。这个问题可能会导致某些应用程序无法正常运行&#xff0c;给我们带来困扰。…

10本值得阅读的量化交易书籍

什么是量化交易&#xff1f; 量化交易是利用数学模型或算法来创建交易策略并进行交易。量化交易通常由大型机构交易员或对冲基金雇用&#xff0c;他们雇用大量的博士和工程师团队。从历史上看&#xff0c;量化交易领域一直非常隐秘&#xff0c;有效的想法往往受到公司的严密保…

【漏洞复现】Apache_HTTPD_未知后缀名解析

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 upload-labs/Pass-07 上传1.php文件 <?php eval($_REQUEST[6868]);phpinfo();?>访问/upload/1.php.jaychou 蚁剑连接

(后续补充)vue+express、gitee pm2部署轻量服务器

首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 首先 防火墙全部关闭算了 关闭防火墙 systemctl stop firewalld 重新载入防火墙使设置生效 firewall-cmd --reload 后端的 pm2.config.cjs …

react_11

MobX 介绍 需求&#xff0c;组件0 改变了数据&#xff0c;其它组件也想获得改变后的数据&#xff0c;如图所示 这种多个组件之间要共享状态数据&#xff0c;useState 就不够用了&#xff0c;useContext 也不好用了 能够和 react 配合使用的状态管理库有 MobX Redux 其中…

XR Interaction ToolKit

一、简介 XR Interaction Toolkit是unity官方的XR交互工具包。 官方XRI示例地址&#xff1a;https://github.com/Unity-Technologies/XR-Interaction-Toolkit-Examples 2023.3.14官方博客&#xff0c;XRIT v2.3 https://blog.unity.com/engine-platform/whats-new-in-xr-int…

JVM类的声明周期

文章目录 版权声明生命周期概述加载阶段查看内存中的对象 连接阶段连接阶段之验证连接阶段之准备连接阶段之解析 初始化阶段练习题目一练习题目二练习题目三练习题目四 使用阶段卸载阶段总结 版权声明 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明…

【探索Linux】—— 强大的命令行工具 P.13(文件系统 | 软硬链接 | 动态库和静态库)

阅读导航 引言一、文件系统1. 磁盘文件系统2. 磁盘结构&#xff08;1&#xff09;物理结构&#xff08;2&#xff09;存储结构 3. stat 命令4. Linux ext2文件系统 二、软硬链接1. 软连接2. 硬链接 三、动态库和静态库1. 动态库&#xff08;1&#xff09;动态库文件扩展名&…

【蓝桥杯省赛真题43】Scratch神奇哈哈镜 蓝桥杯少儿编程scratch图形化编程 蓝桥杯省赛真题讲解

目录 scratch神奇哈哈镜 一、题目要求 编程实现 二、案例分析 1、角色分析

Go类型嵌入介绍和使用类型嵌入模拟实现“继承”

Go类型嵌入介绍和使用类型嵌入模拟实现“继承” 文章目录 Go类型嵌入介绍和使用类型嵌入模拟实现“继承”一、独立的自定义类型二、继承三、类型嵌入3.1 什么是类型嵌入 四、接口类型的类型嵌入4.1 接口类型的类型嵌入介绍4.2 一个小案例 五、结构体类型的类型嵌入5.1 结构体类…

Ansible中的任务执行控制

一、循环 循环迭代任务 1.简单循环 loop: ##赋值列表- value1- value2- ... {{item}} ##迭代变量名称#实例# --- - name: create filehosts: 172.25.0.254tasks:- name: file modulefile:name: /mnt/{{item}}state: presentloop:- westos_file1- westos_file2 2…