【IMX6ULL驱动开发学习】01.IMX6ULL驱动开发_编写第一个hello驱动(不涉及硬件操作)

 

目录

一、驱动程序编写流程

二、代码编写

2.1 驱动程序hello_drv.c

2.2 测试程序

2.3 编写驱动程序的Makefile

三、上机实验

3.1 NFS 挂载

3.2 测试示例


一、驱动程序编写流程

  • 构造file_operations结构体

  • 在里面填充open/read/write/ioctl成员

  • 注册file_operations结构体 int major = register_chrdev(0, "name", &fops);

  • 入口函数:调用regiister_chrdev

  • 出口函数:调用unregiister_chrdev

  • 辅助信息: class_create/class_destroy   device_create/device_destroy

总结:应用程序调用open/read/write/ioctl,驱动程序就给你提供对应的open/read/write/ioctl,只不过驱动程序的这些函数为了便于管理,故把函数放在file_operations结构体里面,通过 register_chrdev函数把结构体告诉内核,并注册字符设备驱动程序。驱动程序里面有个入口函数,相当于main函数,是装载驱动程序时调用的函数,在入口函数中注册,把结构体放到chrdevs数组里面来,出口函数中反注册,就是把结构体拿掉,在卸载驱动程序时调用的函数。  

二、代码编写

2.1 驱动程序hello_drv.c

参考 driver/char 中的程序,包含头文件,写框架,传输数据:

  • 驱动中实现 open, read, write, release, APP 调用这些函数时,都打印内核信息
  • APP 调用 write 函数时,传入的数据保存在驱动中   
  • APP 调用 read 函数时,把驱动中保存的数据返回给 APP   
  • 需要注意的是,驱动程序和应用程序之间数据传递要使用copy_from_user(hello_buf, buf, len)和copy_to_user(buf, hello_buf, len)
#include "asm/cacheflush.h"
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/backing-dev.h>
#include <linux/shmem_fs.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/uaccess.h>static struct class *hello_class;
static int major;
static unsigned char hello_buf[100];static int hello_open (struct inode *node, struct file *filp)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{unsigned long len = size > 100 ? 100 : size;printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);copy_to_user(buf, hello_buf, len);return len;
}static ssize_t hello_write(struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{unsigned long len = size > 100 ? 100 : size;printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);copy_from_user(hello_buf, buf, len);return len;
}static int hello_release (struct inode *node, struct file *filp)
{printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);return 0;
}/* 1. create file_operations */
static const struct file_operations hello_drv = {.owner      = THIS_MODULE,.read		= hello_read,.write		= hello_write,.open		= hello_open,.release    = hello_release,
};/* 2. register_chrdev *//* 3. entry function */
static int hello_init(void)
{major = register_chrdev(0, "100ask_hello", &hello_drv);/*hello_class = class_create(THIS_MODULE, "hello_class");if (IS_ERR(hello_class)) {printk("failed to allocate class\n");return PTR_ERR(hello_class);}device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  /* /dev/hello */*/    return 0;
}/* 4. exit function */
static void hello_exit(void)
{    /*device_destroy(hello_class, MKDEV(major, 0));class_destroy(hello_class);*/unregister_chrdev(major, "100ask_hello");
}module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

2.2 测试程序

测试程序要实现读、写功能:

./hello_test /dev/xxx abcdef     // 把字符串“abcdeft”发给驱动程序
./hello_test /dev/xxx            // 把驱动中保存的字符串读回来

hello_drv_test.c源码如下

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>/* 写: ./hello_test /dev/xxx 100ask* 读: ./hello_test /dev/xxx*/
int main(int argc, char **argv)
{int fd;int len;char buf[100];if (argc < 2){printf("Usage: \n");printf("%s <dev> [string]\n", argv[0]);return -1;}// openfd = open(argv[1], O_RDWR);if (fd < 0){printf("can not open file %s\n", argv[1]);return -1;}if (argc == 3){// writelen = write(fd, argv[2], strlen(argv[2])+1);printf("write ret = %d\n", len);}else{// readlen = read(fd, buf, 100);buf[99] = '\0';printf("read str : %s\n", buf);}// closeclose(fd);return 0;
}

2.3 编写驱动程序的Makefile

驱动程序中包含了很多头文件,这些头文件来自内核,不同的 ARM 板它的某些头文件可能不同。所以编译驱动程序时,需要指定板子所用的内核的源码路径。要编译哪个文件?这也需要指定,设置 obj-m 变量即可怎么把.c 文件编译为驱动程序.ko?这要借助内核的顶层 Makefile。

本驱动程序的 Makefile 内容如下:

KERN_DIR = /home/me/Linux-4.9.88 :指定内核目录

先设置好交叉编译工具链,编译好你的板子所用的内核,然后修改 Makefile指定内核源码路径,最后即可执行make命令编译驱动程序和测试程序。 

三、上机实验

3.1 NFS 挂载

我们是在 Ubuntu 中编译程序,但是需要在 ARM 板子上测试。所以需要把程序放到 ARM 板子上。启动单板后,可以通过 NFS 挂载 Ubuntu 的某个目录,访问该目录中的程序。

ifconfig eth0 192.168.5.9                    //静态配置开发板ip地址 
mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt //挂载到开发板上的mnt目录下
echo "7 4 1 7" > /proc/sys/kernel/printk     //打开内核打印信息

 

3.2 测试示例

首先在开发板的mnt目录下查看文件是否挂载成功,当前目录下以及有了Ubuntu编译好的驱动程序和测试文件

insmod hello_drv.ko   // 安装驱动程序
ls /dev/hello -l      // 驱动程序会生成设备节点
./hello_drv_test      // 查看测试程序的用法

 显示已载入系统的模块

 

查看测试程序用法,并写入字符串"abcdef"后读出,测试结果如下: 

 

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

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

相关文章

使用IDEA操作Mysql数据库

idea中自带了关于数据库的连接 首先要确保你的MySQL正在运行中 打开idea找到database&#xff08; view —> Tool Windows —> database&#xff09;&#xff0c;大家也可以定个快捷键&#xff0c;方便以后日常操作 就是这个样子&#xff0c;然后点加号 然后就可以编写执…

HCIA---TCP/UDP协议

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 目录 文章目录 一.UDP协议简介 UDP协议的特点&#xff1a; 二.TCP协议简介 TCP协议特点 三.TCP和UDP的区别 四.TCP/IP结构详解 五.TCP运输连接的阶段 ​编…

删除这4个文件夹,流畅使用手机无忧

在现代社会中&#xff0c;手机已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着使用时间的增长&#xff0c;我们可能会遇到手机卡顿和内存不足的问题&#xff0c;让我们感到十分困扰。手机卡顿不仅影响使用体验&#xff0c;还可能导致应用程序运行缓慢&#xff0c;甚…

ChatGPT已闯入学术界,Elsevier推出AI工具

2022年11月&#xff0c;OpenAI公司发布了ChatGPT&#xff0c;这是迄今为止人工智能在现实世界中最重要的应用之一。 当前&#xff0c;互联网搜索引擎中出现了越来越多的人工智能&#xff08;AI&#xff09;聊天机器人&#xff0c;例如谷歌的Bard和微软的Bing&#xff0c;看起来…

war和war exploded

war和war exploded的区别 war模式&#xff1a;将WEB工程以包的形式上传到服务器 &#xff1b; war exploded模式&#xff1a;将WEB工程以当前文件夹的位置关系上传到服务器&#xff1b;>> war包是自己打包生成的&#xff0c;如pom文件中<packaging>war</packag…

南卡签约游泳冠军傅园慧,创造防水运动耳机的新天花板!

近日&#xff0c;国内骨传导运动耳机龙头品牌NANK南卡&#xff0c;正式官宣知名游泳冠军傅园慧出任品牌形象大使。在此之外&#xff0c;南卡品牌方还特邀了同样作为游泳冠军的孙杨&#xff0c;以及知名演员张新成、流行歌手段奥娟等多位明星来体验旗下的运动耳机&#xff0c;皆…

【从零学习python 】04. Python编程基础:变量、数据类型与标识符

文章目录 变量以及数据类型一、变量的定义二、变量的类型三、查看数据类型 标识符和关键字标识符命名规则命名规范 关键字进阶案例 变量以及数据类型 一、变量的定义 对于重复使用&#xff0c;并且经常需要修改的数据&#xff0c;可以定义为变量&#xff0c;来提高编程效率。…

中间件插件机制

一、插件 在mybatis一类中间件在处理的时候&#xff0c;提供了插件机制&#xff0c;类似于aop机制&#xff0c;可以在方法前、方法后进行拦截并且修改入参获得改变其方法的行为。那么调用的的方法应该也需要使用动态代理活动被插件进行aop的对象。

django处理分页

当数据库量比较大的时候一定要分页查询的 在django中操作数据库进行分页 queryset models.PrettyNum.objects.all() #查询所有 queryset models.PrettyNum.objects.all()[0:10] #查询出1-10列 queryset models.PrettyNum.objects.filter(mobile__contains136)[0:10] …

sentinel简单使用

核心demo&#xff1a; 1 引入依赖: <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-core</artifactId><version>1.8.0</version> </dependency>2 核心代码&#xff1a; 3 限流保护代码&#xff1a;…

Delphi Professional Crack,IDE插件开发和扩展IDE

Delphi Professional Crack,IDE插件开发和扩展IDE 构建具有强大视觉设计功能的单源多平台本机应用程序。 Delphi帮助您使用Object Pascal为Windows、Mac、Mobile、IoT和Linux构建和更新数据丰富、超连接、可视化的应用程序。Delphi Professional适合个人开发人员和小型团队构建…

uniapp scroll-view 隐藏滚动条

/*清除滚动条 - 适配安卓*/::-webkit-scrollbar {width: 0;height: 0;color: transparent;}/*清除滚动条 - 适配IOS*/::-webkit-scrollbar {display: none;}

uni——tab切换

案例展示 案例代码 <view class"tablist"><block v-for"(item,index) in tabList" :key"index"><view class"tabItem" :class"current item.id?active:" click"changeTab(item)">{{item.nam…

小白到运维工程师自学之路 第六十七集(Harbor企业镜像仓库部署)

一、概述 Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;其目标是帮助用户迅速搭建一个企业级的 Docker Registry 仓库服务。它以Docker公司开源的Registry为基础&#xff0c;提供了管理 UI。基于角色的访问控制(Role Based AccessControl)、AD/LDAP集成…

基于Java的新闻全文搜索引擎的设计与实现

中文摘要 本文以学术研究为目的&#xff0c;针对新闻行业迫切需求和全文搜索引擎技术的优越性&#xff0c;设计并实现了一个针对新闻领域的全文搜索引擎。该搜索引擎通过Scrapy网络爬虫工具获取新闻页面&#xff0c;将新闻内容存储在分布式存储系统HBase中&#xff0c;并利用倒…

RabbitMQ - 简单案例

目录 0.引用 1.Hello world 2.轮训分发消息 2.1 抽取工具类 2.2 启动两个工作线程接受消息 2.4 结果展示 3.消息应答 3.1 自动应答 3.2 手动消息应答的方法 3.3 消息自动重新入队 3.4 消息手动应答代码 4.RabbitMQ 持久化 4.1 队列如何实现持久化 4.2 消息实现持久化 5.不…

面试热题(LRU缓存)

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c;否则返回 -1 …

OB数据库基础知识(学习记录)

目录 OB业务场景 公司使用理由&#xff1a; 常见 bootstrap 失败原因 常见OBD 部署 失败原因 Grafana 查看集群资源由各个节点的聚合情况 OB创建租户 表分组的场景 mysqldump到处数据库schema&#xff0c;数据库数据&#xff0c;表数据 数据同步框架 DATAX obdumper…

MongoDB文档-进阶使用-MongoDB索引-createindex()与dropindex()-在MongoDB中使用正则表达式来查找

阿丹&#xff1a; 之前研究了MongoDB的基础增删改查。在学会基础的数据库增删改查肯定是不够的。这个时候就涉及到了数据库搜索的时候的效率。需要提高数据的搜索效率。 MongoDB索引 在所以数据库中如果没有数据索引的时候。如果需要查找到一些数据。都会去主动扫描所有可能存…

开源代码分享(12)—考虑负荷曲线的配电网扩展规划(附matlab代码)

1.背景介绍 电力系统&#xff08;SEP&#xff09;不断扩展&#xff0c;以满足电力消费者的需求。在这个背景下&#xff0c;配电系统扩展规划&#xff08;PESD&#xff09;确定了配电网络扩展的指导方针。除了SEP的扩展之外&#xff0c;现代化和新技术的出现&#xff0c;例如分布…