linux设备驱动编写入门
linux设备驱动是什么,我个人的理解是liunx有用户态和内核态,用户空间中是不能直接对设备的外设进行使用而内核态中却可以,这时我们需要在内核空间中将需要的外设驱动起来供用户空间使用。linux的驱动主要分为字符设备、块设备、和网络设备三类,在分别驱动时需要注意一下,其中驱动不一定单属于哪一类,一个驱动可能属于多种分类。
一、主备材料
可以根据自己的需要准备相应材料,以下是我自己使用的:
开发环境:VMware
操作系统:ubuntu
开发版:湃兔i2S-6UB
二、下载linux内核源码
1.ubuntu内核源码的下载方式,直接通过命令下载即可,下载后源码存放的地址在/usr/src路径下
sudo apt-get install linux-source
经过的测试好像ubuntu不需要下载源码也是可以编写驱动的,具体教程见后面内容。
2.湃兔核的内核源码下载地址:http://i2som-zh.oss-cn-beijing.aliyuncs.com/i2SOM-iMX-Linux-706035a.tar.gz。
下载完成后解压到开发环境的路径下,具体路径根据个人爱好。
三、编写驱动
1.入口函数和出口函数
学习编程语言时,代码都会有开始运行的位置,也就是我们所知的入口函数'mian()',同样的原理linux驱动编写也是有入口函数的,只是linux驱动比较特殊,函数基本都是成对存在的,有入口便有出口,所以linux存在入口函数和出口函数,如下所示
module_init(x) //入口函数
module_exit(x) //出口函数
留意过内核源码的小伙伴都知道,入口和出口函数的定义是在liunx内核源码中的include/linux/init.h文件中,如下图所示:

2.打印函数
linux的驱动中打印日志到控制台的函数和用户空间的打印函数函数名不一样,但是功能和使用方法差不多,linux内核的打印函数是printk()。
打印函数的定义是在liunx内核源码中的include/linux/printk.h文件中,如下图所示:

3.编写hello.文件
创建一个hello的驱动文件夹,然后创建hello.c文件,文件内容如下
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
static int __init hello_init(void)
{
printk("hello_init\r\n");
return 0;
}
static void __exit hello_exit(void)
{
printk("hello_exit\r\n");
}
/*
*模块入口与出口函数
*/
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jiaozhu");
4.编写Makefile文件
编写完驱动程序后,需要创建Makefile文件,在这里需要注意x86和arm架构环境下的内容有所不同
x86架构下的Makefile内容如下所示
KERNELDIR := /lib/modules/5.8.0-59-generic/build
CURRENT_PATH := $(shell pwd)
obj-m := hello.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
注意:ubuntu的所需的内核源码路径在/lib/modules/5.8.0-59-generic/build下
arm架构下的Makefile内容如下所示
KERNELDIR := /home/i2SOM-iMX-Linux
CURRENT_PATH := $(shell pwd)
obj-m := hello.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
注意:编写arm架构的驱动是需要设置交叉编译器,这里没在Makefile文件中设置交叉编译器的原因是我已经在源码的顶层路径Makefile文件中设置了。
5.编译
完成hello.c文件和Makefile文件的编写后,就可以进行编译了,使用make命令进行编译,编译完成完成后会生成.ko文件,如下图所示:

到此驱动的编写已经完成了,细心的小伙伴可能已经注意到我加载和卸载驱动时没有日志输出,具体原因我也不知道,在arm开发板中测试时是有日志输出的。
四、测试
编译完成后生成的hello.ko驱动模块可以通过insmod和modprobe命令加载模块。
1.ubuntu中使用modprobe命令加载模块时需要将.ko文件拷贝到/lib/modules/5.8.0-59-generic路径下,然后在进行加载
sudo cp hello.ko /lib/modules/5.8.0-59-generic -f
sudo depmod
sudo modprobe hello
注意:/lib/modules/5.8.0-59-generic具体的路路径可能不一样,可以进入/lib/modules/目录下查看。
2.arm开发板中使用modprobe命令加载模块时需要将.ko文件拷贝到/lib/modules/路径下,如果路径不存在直接创建相应的路径即可,arm一般测试方式都是通过nfs挂载根文件系统的形式进行测试。
在开发环境中将.ko文件拷贝至rootfs跟文件系统的/lib/modules路径下
sudo cp hello.ko /home/rootfs/lib/modules -f
然后启动开发板,执行加载命令
depmod
modprobe hello
3.查看加载的驱动和卸载驱动
在任意路径下使用lsmod命令即可查看驱动模块,如下图所示:

完成后可以通过rmmod hello卸载驱动模块,注意在ubuntu下可能需要通过root权限才能卸载。
到此我们简单的驱动模块已经编写完成,有写得不好的地方忘各位大佬支出。
参考文献
【驱动】linux设备驱动·入门:https://www.cnblogs.com/lcw/p/3159386.html。
正点原子视屏教程:https://www.bilibili.com/video/BV1fJ411i7PB?p=3。
linux设备驱动编写入门的更多相关文章
- linux设备驱动编写_tasklet机制
在编写设备驱动时, tasklet 机制是一种比较常见的机制,通常用于减少中断处理的时间,将本应该是在中断服务程序中完成的任务转化成软中断完成. 为了最大程度的避免中断处理时间过长而导致中断丢失,有时 ...
- linux设备驱动编写_tasklet机制(转)
在编写设备驱动时, tasklet 机制是一种比较常见的机制,通常用于减少中断处理的时间,将本应该是在中断服务程序中完成的任务转化成软中断完成. 为了最大程度的避免中断处理时间过长而导致中断丢失,有时 ...
- [ARM-LInux开发]linux设备驱动makefile入门解析
以下内容仅作参考,能力有限,如有错误还请纠正.对于一个普通的linux设备驱动模块,以下是一个经典的makefile代码,使用下面这个makefile可以完成大部分驱动的编译,使用时只需要修改一下要编 ...
- 【驱动】linux设备驱动·入门
linux设备驱动 驱动程序英文全称Device Driver,也称作设备驱动程序.驱动程序是用于计算机和外部设备通信的特殊程序,相当于软件和硬件的接口,通常只有操作系统能使用驱动程序. 在现代计算机 ...
- 【驱动】linux设备驱动·字符设备驱动开发
Preface 前面对linux设备驱动的相应知识点进行了总结,现在进入实践阶段! <linux设备驱动入门篇>:http://infohacker.blog.51cto.com/6751 ...
- 浅谈Android系统移植、Linux设备驱动
一.Android系统架构 第一层:Linux内核 包括驱动程序,管理内存.进程.电源等资源的程序 第二层:C/C++代码库 包括Linux的.so文件以及嵌入到APK程序中的NDK代码 第三层:An ...
- linux设备驱动概述,王明学learn
linux设备驱动学习-1 本章节主要学习有操作系统的设备驱动和无操作系统设备驱动的区别,以及对操作系统和设备驱动关系的认识. 一.设备驱动的作用 对设备驱动最通俗的解释就是“驱使硬件设备行动” .设 ...
- linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-119723.html linux设备驱动归纳总结(十三):1.触摸屏与ADC时钟 xxxxxxxxxx ...
- linux设备驱动归纳总结(十二):简单的数码相框【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-116926.html linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxx ...
随机推荐
- Ubuntu 20.04 配置多网卡链路聚合
Ubuntu 20.04 配置多网卡链路聚合 多网卡IP配置 首先查看网卡信息 root@it:~# ip add 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65 ...
- 测试 USB 存储设备读写性能(Mb/s),平均读写速度等
1.将U盘(USB3.0)插入被测试机器,假定识别设备为sdc2.创建vfat文件系统分区/dev/sdb1分区容量大于30GBumount /dev/sdc1mkfs -t vfat /dev/sd ...
- 037.Python的UDP语法
UDP语法 1 创建一个socket的UDP对象 import socket #创建对象 socket.SOCK_DGRAM 代表UDP协议 sk = socket.socket(type=socke ...
- git cherry-pick(不同分支的提交合并)
git cherry-pick可以选择某一个分支中的一个或几个commit(s)来进行操作.例如,假设我们有个稳定版本的分支,叫v2.0,另外还有个开发版本的分支v3.0,我们不能直接把两个分支合并, ...
- C语言中位运算异或“∧”的作用
1.概念异或运算符"∧"也称XOR运算符.它的规则是若参加运算的两个二进位同号,则结果为0(假):异号则为1(真).即 0∧0=0,0∧1=1, 1^0=1,1∧1=0.运算 ...
- 技术干货 | 如何在 Library 中使用/依赖 mPaaS?
使用场景 在使用 mPaaS 框架过程中,有时需要复用模块.复用时需要按照使用 Module 依赖的方式添加模块.本文以将复用 mPaaS 扫码组件的 Module 为例进行说明. 前提条件 已按照原 ...
- flink反压的监控
反压在流式系统中是一种非常重要的机制,主要作用是当系统中下游算子的处理速度下降,导致数据处理速率低于数据接入的速率时,通过反向背压的方式让数据接入的速率下降,从而避免大量数据积压在flink系统中,最 ...
- 使用vue-i18n实现中英文切换(内含动态属性的绑定)
最近做学生管理系统,因为有国外的学生,所以要进行中英文切换,查了查Vue中使用vue-i18n插件能够实现网页的中英文切换,学习内容如下: 一.下载vue-i18n插件 npm install vue ...
- 上传靶机实战之upload-labs解题
前言 我们知道对靶机的渗透可以提高自己对知识的掌握能力,这篇文章就对上传靶机upload-labs做一个全面的思路分析,一共21个关卡.让我们开始吧,之前也写过关于上传的专题,分别为浅谈文件上传漏洞( ...
- opentack - 本地化
目录 1 Openstack minimal component 1 组件与功能 2 集群数据存储 2 neutron控制端和计算节点 2.1 SDN网络实现方式 2.2 安全组实现 2.3 虚拟机内 ...