前言基于上一个博文对 linux驱动的认知的了解,那么现在开始我们正式来进入学习基于驱动框架来编写驱动代码,那么接下来我们先来看看一个最简单的驱动框架代码

一、字符设备驱动框架代码与应用层代码

驱动框架代码

#include <linux/fs.h>       //file_operations声明
#include <linux/module.h>    //module_init  module_exit声明
#include <linux/init.h>      //__init  __exit 宏定义声明
#include <linux/device.h>  //class  devise声明
#include <linux/uaccess.h>   //copy_from_user 的头文件
#include <linux/types.h>     //设备号  dev_t 类型声明
#include <asm/io.h>          //ioremap iounmap的头文件static struct class *pin4_class;
static struct device *pin4_class_dev;static dev_t devno;                //设备号
static int major =231;            //主设备号
static int minor =0;              //次设备号
static char *module_name="pin4";   //模块名--这个模块名到时候是在树莓派的/dev底下显示相关驱动模块的名字//led_open函数
static int pin4_open(struct inode *inode,struct file *file)
{printk("pin4_open\n");  //内核的打印函数和printf类似    return 0;
}//led_write函数
static ssize_t pin4_write(struct file *file,const char __user *buf,size_t count, loff_t *ppos)
{printk("pin4_write\\n");return 0;
}static ssize_t pin4_read(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{printk("pin4_read\n");return 0;
}static struct file_operations pin4_fops = {.owner = THIS_MODULE,.open  = pin4_open,.write = pin4_write,.read  = pin4_read,
};int __init pin4_drv_init(void)   //设备驱动初始化函数(真实的驱动入口)
{int ret;devno = MKDEV(major,minor);  //创建设备号ret   = register_chrdev(major, module_name,&pin4_fops);  //注册驱动  告诉内核,把这个驱动加入到内核驱动的链表中pin4_class=class_create(THIS_MODULE,"myfirstdemo"); //这个是让代码在/dev目录底下自动生成设备,自己手动生成也是可以的pin4_class_dev =device_create(pin4_class,NULL,devno,NULL,module_name);  //创建设备文件return 0;
}void __exit pin4_drv_exit(void)  //卸载驱动,即将驱动从驱动链表中删除掉
{device_destroy(pin4_class,devno);class_destroy(pin4_class);unregister_chrdev(major, module_name);  //卸载驱动
}module_init(pin4_drv_init);  //真正的入口
module_exit(pin4_drv_exit);  //卸载驱动
MODULE_LICENSE("GPL v2");

驱动框架代码里面都有相对应的注释,用心去看还是很好看懂的。

操作驱动的应用层代码

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main()
{int fd;fd = open("/dev/pin4",O_RDWR);if(fd < 0){printf("fail to open the pin4\n");perror("the reason:");}else{printf("success to open the pin4\n");}write(fd,'2',1);return 0;
}

二、如何让编写好的驱动代码生效

2.1 首先得把上面两个代码文件先拿进linux虚拟机里面来,记住只要将驱动框架代码那个文件拿进到内核源码树目录底下对应的目录即可,那个应用层的测试代码就放在工作目录底下即可
进入驱动设备目录:

cd SYSTEM/linux-rpi-4.14.y/drivers/char/

为什么会是这个目录呢?
因为drivers就是驱动相关的目录,然而char是指字符型驱动设备的意思,由于IO口的驱动设备属于字符设备。

方式一:先拿进来工作目录底下,然后再拷贝到内核源码树目录底下对应的驱动设备目录底下,其实方式一可以是通过拖拽的方式将文件拉进虚拟机里面,也可以通过filezila传输文件

上图中的 ~/是指工作目录的意思(即/home/pi./就是指当前目录的意思

方式二:直接用filezila将文件传输到对应的目录下即可

2.2 修改Makefile文件,告诉编译器要对该驱动文件进行编译
温馨提示:一定要记住,我们把驱动文件放在了那个目录下,就去修改那个目录下的Makefile,例如我们现在是将驱动文件放在了char目录底下,所以我们就要去修改这个目录底下的Makefile文件

配置Makefile成模块的形式
2.2.1 进入Makefile文件:

2.2.2 在Makefile添加以下内容:

obj-m                           += pin4_driver.o

拓展解释:

obj-m  +=  xxx.o    //m是编译成module(模块)
obj-y  +=  xxx.o    //y是编译进 kernel 只可以看到.o 不会生成ko

修改后的Makefile

2.3 修改完Makefile之后,要做的就是对这个驱动文件进行编译

2.3.1 这个一定要记住,不是在/char目录下进行编译,而是在内核源码树目录底下进行编译
编译指令:

 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules//指定架构是arm架构//交叉编译工具链是arm-linux-gnueabihf-//KERNEL=kernel7 是指内核的版本的意思//modules 生成模块

编译:

编译完成后会在/char目录底下生成一个.ko文件

在这顺便把应用层文件也进行编译了
在工作目录底下进行

指令:arm-linux-gnueabihf-gcc pin4_test.c -o pin4test

两个文件都进行编译生成对应的文件之后,通过filezila或者scp的方式将.ko 文件和pin4test文件传输到树莓派底下,两种传输方式在前面的博文里也有介绍。

温馨提示:如果是通过filezila的方式将可执行文件(pin4test)先传输到windows再从windows传输到树莓派的话,这样文件在树莓派底下是没有可执行权限的,那么怎样才能让它有可执行权限呢?
执行以下指令即可:chmod +x xxx(文件名),这样就让文件具有了可执行的权限

完成以上操作,在linux虚拟机端的事情就完了,接下来来到了树莓派端的操作。

三、如何让写到的驱动在树莓派底下生效

3.1 在树莓派的工作目录底下可以看到从虚拟机上传过来的两个文件,分别是驱动代码文件,一个是应用层的可执行文件

3.2 接下来讲解一下如何在树莓派底下将驱动装载与及卸载
驱动装载指令:sudo insmod xxx.ko

然后在驱动目录底下可以看到一个名为pin4的驱动

为什么会是名为pin4的驱动呢?
因为这是在驱动代码文件里面设定好的,这个驱动的名字是随意更改的,但一般都设置为驱动相关的。

3.3 不要以为装了驱动就可以执行相关的测试程序

在上图中就是显示即使是装了驱动,测试程序也一样是跑不起来,那么这是为什么呢?

在上图中我们可以看到这个驱动文件是没有任何人都可读可写的权限的,所以我们要给这个驱动文件加上所有人都可读可写的权限

加上权限的指令:sudo chmod 666 /dev/pin4 666是所有人都可访问的意思

执行这个指令后

从图中可看出,现在跟上面那图比较,pin4这个驱动文件明显就是多了可读可写的权限

3.4 测试驱动是否可以装载成功

在上图中我们可以看到已经测试出已经把驱动文件装载成功,并且相关的测试程序也可以跑起来了

但在驱动代码里我们看到并不是打印这些内容的,那是为什么呢?
因为我们看到的都是应用层的东西,驱动的代码输出是属于内核层的东西,所以我们要用一个指令将内核层的输出东西输出到应用层来才能看到

查看内核层的内容的指令:dmesg

由上图中,我们可以看出,内核层已经有了相关的信息输出,这样就说明了我们已经是驱动装载成功的了

3.5 驱动模块的查看与卸载

3.5.1 显示已经装进系统的驱动模块:lsmod

3.5.2 卸载指令:sudo rmmod xxx 这里就不需要写.ko


在上图中可以看到,驱动已经是被卸载的了

内核驱动验证的步骤:

 a.装载驱动 b.驱动装载后生成设备,比如/dev/pin4,通过sudo chmod 666 /dev/pin4 来添加访问权限 c.运行测试程序(pin4test)调用驱动d.内核的printk是内核层的printf,通过dmesg查看打印信息

学习笔记,仅供参考

基于驱动框架编写驱动代码相关推荐

  1. 基于框架编写驱动代码

    操作驱动的上层代码(pin4test) #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> ...

  2. 树莓派学习笔记(十三)基于框架编写驱动代码

    文章目录 一.代码分析: 二.源码 一.代码分析: 在内核中由于代码文件多,避免函数名重复,使用static将函数的作用域限制在该文件内 内核的打印函数printk和printf类似 file_ope ...

  3. linux驱动框架和驱动代码

    一.linux文件系统:         1.什么是文件系统               文件系统是操作系统用于明确存储设备组织文件的方法. 以上说的方法:就是文件管理系统(程序),简称文件系统   ...

  4. Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析 (iic驱动框架,i2c驱动框架)...

    转载于 : http://blog.csdn.net/zqixiao_09/article/details/50917655 关于Exynos4412 IIC 裸机开发请看 :Exynos4412 裸 ...

  5. S3C2440 开发板实战(7):字符设备驱动框架+LED驱动

    在学习驱动的时候我遇到了很多问题,所以我的学习路线是这样的: 编写驱动发现.ko文件需要放入开发板的目录中,然后就学习通过nfs创建共享文件,在配置nfs时发现网络没有连接上,所以就学习怎样配置IP地 ...

  6. 基于简单字符设备驱动框架编写代码驱动io_2

    更具体步骤查看: https://blog.csdn.net/oNelson123/article/details/110726961 https://blog.csdn.net/qq_2825888 ...

  7. linux-I2C驱动(4)--编写驱动代码

    开发板:讯为电子itop4412开发板,实测可行. 示例代码: #include <linux/kernel.h> #include <linux/module.h> #inc ...

  8. android lcd驱动框架,LCD驱动及Framebuffer相关(转载)

    LCD驱动及Framebuffer相关 (2012-11-20 17:04) 标签:&nBSP; lcd驱动  framebuffer  io内存  分类: Android驱动模块相关 内容提 ...

  9. Stata:毕业论文大礼包 C——基于 esttab 框架编写的实证结果输出命令

    作者:王美庭 (中南民族大学经济学院) Email: 2017110097@mail.scuec.edu.cn Stata连享会   计量专题 || 精品课程 || 简书推文 || 公众号合集   连 ...

最新文章

  1. javascript小数四舍五入
  2. 计算机学院迎新活动总结,大学迎新活动总结
  3. python杨辉三角编程_Python基础练习实例49(打印杨辉三角)
  4. c语言中精度站的字节,C语言学习--一些细节问题
  5. 洛谷P3413 SAC#1 - 萌数(数位dp)
  6. 将web项目部署到阿里云服务器上
  7. 如虎添翼VSPHERE 4/5 环境下 linux/windows 动态扩展磁盘
  8. 计算机网络图标显示不出来,网络图标不见了汇总解决教程
  9. 无法加载 Chrome PDF Viewer
  10. 人工神经网络基本构成有哪些,常见的人工神经网络有哪几种
  11. 根据身份证获取性别、生日、后六位
  12. linux消息队列 性能,消息队列消息总大小的问题
  13. ONLYOFFICE 如何连接集成到 Wordpress 上
  14. C++实现十进制转换
  15. 异常:could not initialize proxy - the owning Session was closed
  16. 2022年中国服务外包行业发展现状及未来发展趋势分析:执行额达1753.5亿美元,同比增长10.92%[图]
  17. stp实验心得_实验报告STP
  18. 嵌入式开发模拟红外测距仪---UDP通信实现无线装置
  19. P93-好玩游戏的物品清单
  20. java基础之包_繁星漫天_新浪博客

热门文章

  1. CentOS7救援模式重置root密码
  2. 计算机组成原理之外围设备
  3. 大众点评网的网站架构
  4. 利用java代码一键生成数据库文档
  5. Rocket MQ发送消息报错: service not available now
  6. Exercise11-Matplotlib
  7. SuperZero gero同步区块进度可视化
  8. 那些年不容错过的115家硅谷IT公司
  9. 新编《守株待兔》—C语言版—兼聊为什么不应该用%d格式转换输出指针
  10. CPP-week thirteen