Linux驱动开发-字符设备驱动开发

Linux驱动开发-字符设备驱动开发

  • 一,Linux驱动开发
  • 二,字符设备驱动开发
    • 1.具体实现
      • 2.1.1驱动模块具体函数实现
      • 2.1.2 应用调试模块具体函数实现
      • 2.1.3 Makefile
      • 2.1.4 进行测试
        • 2.1.4.1创建节点
        • 2.1.4.2 加载和卸载驱动模块
        • 2.1.4.3 测试
    • 2.字符设备驱动应用程序(linux应用)调用驱动程序(linux驱动)
  • 三,其他小问题
    • 1.内核中的加载函数为什么前面有__init
    • 2.设备树干什么用
    • 3.内核空间和用户空间

一,Linux驱动开发

  Linux 驱动是内核的一部分,负责管理硬件设备并与用户空间程序交互,使操作系统能够控制硬件设备(如网卡、显卡、传感器等)。
  驱动类型:①字符设备驱动:以字节流方式访问设备,包括,IIC,SPI,按键,键盘,鼠标,串口和LED。②块设备驱动:以块为单位访问,包括硬盘,SSD和SD卡。③网络设备驱动:管理网络接口,处理数据包的发送和接收。

二,字符设备驱动开发

  驱动有两种方式:①将驱动编写到内核中,内核启动时就会自动运行驱动程序。②将驱动编译成模块(.ko),内核启动后使用命令加载驱动模块。下面的选择第二种。
在这里插入图片描述

1.具体实现

2.1.1驱动模块具体函数实现

#include <linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/fs.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/types.h>


#define CHRDEVBASE_MAJOR 200 //设备号
#define CHRDEVBASE_NAME "chrdevbase" //设备名
static char readbuf[100],writebuf[100];
static char kernel_date[100]={"kernel date 88888"};

static int chrdevbase_open(struct inode *inode,struct file *filp)
{
    //printk("OPEN FILE!!!\r\n");
    return 0;//为0时,证明打开了,其他值说明出现错误
}
static int chrdevbase_release(struct inode *inode,struct file *filp)
{
    //printk("CLOSE FILE!!!\r\n");
    return 0;//为0时,证明打开了,其他值说明出现错误
}
static ssize_t chrdevbase_read(struct file *filp,__user char *buf,size_t count,loff_t *ppos)
{
    //printk("READ FILE!!!\r\n");
    int ret = 0;
    memcpy(readbuf,kernel_date,sizeof(kernel_date));
    ret = copy_to_user(buf,readbuf, count);
    if(ret == 0)
    {
        printk("read_kernel_success\r\n");
    }else printk("read_kernel_error\r\n");
    return 0;
}
static ssize_t chrdevbase_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
    //printk("WRITE FILE!!!\r\n");
    int ret = 0;
    ret = copy_from_user(writebuf, buf,count);
    if(ret == 0)
    {
        printk("write_kernel_success,write date=%s\r\n",writebuf);

    }else printk("write_kernel_error\r\n");
    return 0;
}
static struct  file_operations chrdevbase_fops={
    .owner = THIS_MODULE,
    .open = chrdevbase_open,
    .release = chrdevbase_release,
    .read = chrdevbase_read,
    .write = chrdevbase_write,
};
static int __init chrdevbase_init(void)//加载函数
{
    int ret = 0;
    printk("INIT\r\n");
    /*注册字符设备*/
    ret = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME,&chrdevbase_fops);
    if(ret<0)
    {
        printk("INIT ERROR\r\n");
    }
    return 0;
}
static void __exit chrdevbase_exit(void)//卸载函数
{
   printk("EXIT\r\n");
    /*注消字符设备*/
    unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
}

module_init(chrdevbase_init);//入口
module_exit(chrdevbase_exit);//出口

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wyt");

2.1.2 应用调试模块具体函数实现

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

/*具体在串口输入比如读:./chrdevAPP /dev/chrdevbase 1       1表示读,如果是写操作 后面换成2*/
int main(int argc,char *argv[])
//argc:应用程序串口输入的参数个数 ,argc[]:具体参数内容,字符串格式,这个就是串口输入,比如argv[0]就是./chrdevAPP
{

    int ret = 0;
    int fd =0;
    char read_buf[100],write_buf[100];
    char *filename;
    filename = argv[1];
    char write_date[100]={"CCCCCC  NNNNNN CCCCCC"};
    if(argc!=3)//判断输入是不是三个变量
    {
        printf("input error!");
        return -1;
    }
    /*open*/
    fd = open(filename, O_RDWR);//打开文件函数,打开为0,不然为-1
    // if(fd<0)
    // {
    //     //printf("cannot open file(APP)\r\n");
    //     return -1;
    // }
    if(atoi(argv[2]) == 1)//atoi函数将字符串转化为int型
    {
        /*read*/
        ret = read(fd, read_buf,30);
        if(ret==0)
        {
         printf("kernel date =%s\r\n",read_buf);
            return 0;
        }
    }
    if(atoi(argv[2]) == 2)
    {
        /*write*/
        memcpy(write_buf,write_date,sizeof(write_date));
        ret = write(fd,write_buf,30);
        if(ret<0)
        {
            //printf("cannot write file(APP)\r\n");
            return -1;
        }
    }
    /*close*/
    ret =close(fd);
    if(ret<0)
    {
        printf("cannot close file(APP)\r\n");
        return -1;
    }   
    return 0;
}

2.1.3 Makefile

KERNELDIR :=/home/wyt/linux/linux-imx-rel_imx_4.1.15_2.1.0_alientek 
//指定内核源码路径

CURRENT_PATH := $(shell pwd) //获取当前路径

obj-m := chrdevbase.o //obj-m会将.c编译为.ko文件

build: kernel_modules //定义构建目标build,依赖于kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
//$(MAKE) 即make命令   -C $(KERNELDIR):切换到内核源码目录执行编译  
//指定模块源码所在目录,最终实现 在内核源码目录下,使用当前目录中的原码编译出内核模块
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean//在内核源码目录下,清理当前目录编译生成的文件

2.1.4 进行测试

2.1.4.1创建节点

  驱动加载需要在/dev/下创建一个与之对应的字符设备节点,应用程序通过操作这个节点文件从而对具体设备完成具体操作。c代表字符型设备,200是主设备号,0次设备号。
在这里插入图片描述

2.1.4.2 加载和卸载驱动模块

  创建/lib/modules/4.1.15目录,利用modprobe命令加载驱动模块(若出现cant open modules.dep,使用depmod命令即可)。

在这里插入图片描述查看当前系统中是否有chrdevbase这个设备:
请添加图片描述
卸载驱动模块:
在这里插入图片描述

2.1.4.3 测试

读(1)和写(2)操作:
在这里插入图片描述

2.字符设备驱动应用程序(linux应用)调用驱动程序(linux驱动)

在这里插入图片描述
在这里插入图片描述

  C库中函数通过到系统调用到内核的过程:C库函数内部会调用系统调用,将请求传递给内核,每个系统调用都有一个唯一的系统调用号,系统调用参数通过寄存器传递给内核,通过软中断触发从用户空间到内核空间的切换,内核会根据系统调用号找到对应的处理函数,执行具体操作,然后将结果返回给用户空间。

三,其他小问题

1.内核中的加载函数为什么前面有__init

  static int __init chrdevbase_init(void)加上__init:__init 是一个宏,用于标记初始化函数,作用是告诉编译器这个函数放在内核的初始化段中,从而在函数执行完后释放其占用的内存。同理__exit:用于标记模块的退出函数,表示该函数在模块卸载时执行。

2.设备树干什么用

  简单来说就是让不同的板子能够使用一个内核+不同的设备树,从而不用频繁更改内核了。设备树是一种硬件信息的数据结构,使得内核支持多种硬件平台。在传统方式中,硬件信息直接硬编码在内核源码中,导致内核难以支持多种硬件平台,使用设备树后,硬件信息独立于内核源码,内核通过解析设备树文件获取硬件信息。硬件信息包括:CPU架构,内存布局,外设信息,中断控制和时钟配置。

3.内核空间和用户空间

 &emsp①内核空间:操作系统运行的区域,只有内核代码能访问,特点有:最高权限,内核空间内存有保护,用户空间程序无法直接访问,稳定性高。主要管理CPU,内存和网络等;提供系统调用接口;实现进程调度,内存管理和文件系统等核心功能。
 &emsp②用户空间:用户程序运行的空间,包括应用程序和库函数,通过系统调用访问内核空间,特点:运行在较低级别,只能访问自己的内存区域,稳定性较低。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

e2studio开发RA4M2(17)----ADC扫描多通道采样

e2studio开发RA4M2.17--ADC扫描多通道采样 概述视频教学样品申请硬件准备参考程序源码下载ADC属性配置回调函数主程序演示结果 概述 在嵌入式系统中&#xff0c;ADC&#xff08;模数转换器&#xff09;是一个非常重要的组件&#xff0c;它将模拟信号转换为数字信号。为了提高采…

编写一个基于OpenSSL的SSL/TLS服务端(HTTPS)可运行的完整示例

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

MyBatis的关联映射

前言 在实际开发中&#xff0c;对数据库的操作通常会涉及多张表&#xff0c;MyBatis提供了关联映射&#xff0c;这些关联映射可以很好地处理表与表&#xff0c;对象与对象之间的的关联关系。 一对一查询 步骤&#xff1a; 先确定表的一对一关系确定好实体类&#xff0c;添加关…

利用Git和wget批量下载网页数据

一、Git的下载&#xff08;参考文章&#xff09; 二. wget下载&#xff08;网上很多链接&#xff09; 三、git和wget结合使用 1.先建立一个文本&#xff0c;将代码写入文本&#xff08;代码如下&#xff09;&#xff0c;将txt后缀改为sh&#xff08;download_ssebop.sh&#xf…

deepseek助力运维和监控自动化

将DeepSeek与Agent、工作流及Agent编排技术结合&#xff0c;可实现IT运维与监控的智能化闭环管理。以下是具体应用框架和场景示例&#xff1a; 一、智能Agent体系设计 多模态感知Agent 日志解析Agent&#xff1a;基于DeepSeek的NLP能力&#xff0c;实时解析系统日志中的语义&a…

从零开始实现机器臂仿真(UR5)

1. UR5软件配置 # 安装 MoveIt! 依赖 sudo apt install ros-humble-moveit ros-humble-tf2-ros ros-humble-moveit-setup-assistant ros-humble-gazebo-ros-pkgs # 安装 UR 官方 ROS2 驱动 sudo apt update sudo apt install ros-humble-ur-robot-driver ros-humble-ur-descri…

h5 IOS端渐变的兼容问题 渐变实现弧形效果

IOS端使用渐变的时候有兼容问题 以下是问题效果&#xff0c;图中黑色部分期望的效果应该是白色的。但是ios端是下面的样子…… 安卓pc 支持&#xff1a; background-image: radial-gradient(circle 40rpx at 100% 0, #f3630c 40rpx, rgb(255, 255, 255) 50%);安卓pc ios支持…

文件上传漏洞与phpcms漏洞安全分析

目录 1. 文件上传漏洞简介 2. 文件上传漏洞的危害 3. 文件上传漏洞的触发条件 1. 文件必须能被服务器解析执行 2. 上传目录必须支持代码执行 3. 需要能访问上传的文件 4. 例外情况&#xff1a;非脚本文件也可能被执行 4. 常见的攻击手法 4.1 直接上传恶意文件 4.2 文件…

DeepSeek 助力 Vue3 开发:打造丝滑的时间选择器(Time Picker)

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的时间选择器(Time Picker)📚前言📚页面效果📚指令输入…

「多开浏览器」颜值升级之「消灭堆叠的窗口」(二)

01 传统指纹浏览器的架构 传统指纹浏览器&#xff08;也称为多用户浏览器或反检测浏览器&#xff09;是一种用于模拟多个独立用户环境的技术工具&#xff0c;主要用于网络爬虫、广告验证、社交媒体管理等场景。其核心目标是通过模拟不同的浏览器指纹&#xff08;Browser Finge…

IndexError: index 0 is out of bounds for axis 1 with size 0

IndexError: index 0 is out of bounds for axis 1 with size 0 欢迎来到英杰社区&#xff0c;这里是博主英杰https://bbs.csdn.net/topics/617804998 报错原因 数组或数据结构为空 如果数组或 DataFrame 在指定的维度上没有任何元素&#xff08;例如&#xff0c;没有列&#x…

本地部署阿里万象2.1文生视频模型(Wan2.1-T2V)完全指南

在生成式AI技术爆发式发展的今天,阿里云开源的万象2.1(Wan2.1)视频生成模型,为创作者提供了从文字/图像到高清视频的一站式解决方案。本文针对消费级显卡用户,以RTX 4060 Ti 16G为例,详解本地部署全流程与性能调优方案,涵盖环境配置、多模型选择策略、显存优化技巧及实战…

[Python学习日记-85] 并发编程之多进程 —— Process 类、join 方法、僵尸进程与孤儿进程

[Python学习日记-85] 并发编程之多进程 —— Process 类、join 方法、僵尸进程与孤儿进程 简介 multiprocessing 模块 Process 类 僵尸进程与孤儿进程 简介 在前面的进程理论的介绍当中我们已经介绍了进程的概念、并发与并行的区别以及进程并发的实现理论&#xff0c;这些都…

飞书考勤Excel导入到自己系统

此篇主要用于记录Excel一行中&#xff0c;单条数据的日期拿取&#xff0c;并判断上下班打卡情况。代码可能满足不了大部分需求&#xff0c;目前只够本公司用&#xff0c;如果需要&#xff0c;可以参考。 需要把飞书月度汇总的考勤表导入系统中可以参考下。 下图为需要获取的年…

Python项目】基于Python的图像去雾算法研究和系统实现

Python项目】基于Python的图像去雾算法研究和系统实现 技术简介&#xff1a;采用Python技术、MYSQL数据库等实现。 系统简介&#xff1a;图像去雾系统主要是基于暗通道先验和逆深度估计技术的去雾算法&#xff0c;系统功能模块分为&#xff08;1&#xff09;图像上传模块&…

游戏引擎学习第135天

仓库:https://gitee.com/mrxiao_com/2d_game_3 回顾 game_asset.cpp 的创建 在开发过程中&#xff0c;不使用任何现成的游戏引擎或第三方库&#xff0c;而是直接基于 Windows 进行开发&#xff0c;因为 Windows 目前仍然是游戏的标准平台&#xff0c;因此首先在这个环境中进行…

【Linux】冯诺依曼体系结构-操作系统

一.冯诺依曼体系结构 我们所使用的计算机&#xff0c;如笔记本等都是按照冯诺依曼来设计的&#xff1a; 截止目前&#xff0c;我们所知道的计算机都是由一个一个的硬件组装起来的&#xff0c;这些硬件又由于功能的不同被分为了输入设备&#xff0c;输出设备&#xff0c;存储器…

[liorf_localization_imuPreintegration-2] process has died

使用liorf&#xff0c;编译没报错&#xff0c;但是roslaunch报错如下&#xff1a; 解决方法&#xff1a; step1: 如果你之前没有安装 GTSAM&#xff0c;可以尝试安装它 step2: 检查是否缺少依赖库 ldd /home/zz/1210/devel/lib/liorf_localization/liorf_localization_imuPr…

模块11_面向对象

文章目录 模块11_面向对象模块十回顾&&模块十一重点 第一章.接口1.接口的介绍2.接口的定义以及使用3.接口中的成员3.1抽象方法3.2默认方法3.3静态方法3.4成员变量3.4成员变量 4.接口的特点5.接口和抽象类的区别 第二章.多态1.多态的介绍2.多态的基本使用3.多态的条件下…

常见webshell工具的流量特征

1、蚁剑 1.1、蚁剑webshell静态特征 蚁剑中php使用assert、eval执行&#xff1b;asp只有eval执行&#xff1b;在jsp使用的是Java类加载&#xff08;ClassLoader&#xff09;&#xff0c;同时会带有base64编码解码等字符特征。 1.2、蚁剑webshell动态特征 查看流量分析会发现…