Linux驱动开发入门 demo
驱动开发时候,尽量选择对应操作系统内核的Linux系统作为上位机平台
下载源码与编译
源码的下载可以从网站:https://mirrors.edge.kernel.org/pub/linux/kernel/
找到对应的内核版本,然后下载,通过make menuconfig和make,进行编译。
没有编译过的内核,驱动开发过程中进行编译可能有错误,找不到文件等。
编写一个最简单的驱动
如下是hello.c文件的驱动程序。其中声明了证书,和模块加载后与退出时应该执行的函数。
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "hello,worldn");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "goodbye,worldn");
}
module_init(hello_init);
module_exit(hello_exit);
编写Makefile文件
Makefile文件的编写如下,主要是KERNELDIR,为linux源码的位置
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-source-5.4.0
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := hello.o
endif
修改部分信息和执行
当编译的内核为系统本身的内核,但是make以后生成的ko文件无法加载,即通过insmod xxx.ko无法加载,格式不对
查看dmesg信息,参考解决:https://www.cnblogs.com/blfbuaa/p/6907027.html
正常执行后再dmesg中会有相应的加载和卸载模块的message信息。卸载命令为rmmod xxx
模块之间的依赖通信
以下为add_sub.c
#include<linux/kernel.h>
#include<linux/module.h>
#include"add_sub.h"
long add_integer(long a,long b)
{
printk(KERN_ALERT "add init");
return a+b;
}
long sub_integer(long a,long b)
{
printk(KERN_ALERT "sub init");
return a-b;
}
EXPORT_SYMBOL(add_integer);
EXPORT_SYMBOL(sub_integer);
MODULE_LICENSE("Dual BSD/GPL");
以下为add_sub.h
#ifndef _ADD_SUB_H_
#define _ADD_SUB_H_
long add_integer(long a,long b);
long sub_integer(long a,long b);
#endif
以下为Makefile,当执行完make后,则生成了符号表文件,其为Module.symvers,该文件可以用于其他文件的函数引用
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-source-5.4.0
PWD := $(shell pwd)
PRINT_INC =$(PWD)/../include
EXTRA_CFLAGS += -I $(PRINT_INC)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := add_sub.o
endif
以下为test.c
#include<linux/kernel.h>
#include<linux/module.h>
#include"../add_sub.h"
static long a = 1;
static long b = 1;
static int AddOrSub = 1;
static int test_init(void)
{
long result = 0;
printk(KERN_ALERT "test initn");
if (1 == AddOrSub)
{
result = add_integer(a,b);
}
else
{
result = sub_integer(a,b);
}
//printk(KERN_ALERT, "the %s result is %ld", AddOrSub==1?"Add":"Sub",result);
return 0;
}
static void test_exit(void)
{
printk(KERN_ALERT, "test_exit");
}
module_init(test_init);
module_exit(test_exit);
module_param(a,long,S_IRUGO);
module_param(b,long,S_IRUGO);
module_param(AddOrSub,int,S_IRUGO);
MODULE_LICENSE("Dual BSD/GPL");
以下为test.c的Makefile
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /usr/src/linux-source-5.4.0
PWD := $(shell pwd)
KBUILD_EXTRA_SYMBOLS=$(obj)/../print/Module.symvers
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := test.o
endif
编译完后,需要先挂载add_sub模块,然后再挂载test模块。
未得到预期的效果,主要是在顺次加载后,并在加载过程添加a,b等参数,无法从dmesg中获得一个调用输出
将模块编译到内核中
如在drivers下建立add_sub_Kconfig文件夹,然后放入对应的源码文件,对应的Makefile和Kconfig文件。其中Kconfig文件用于make menuconfig的索引,其和上层的Kconfig关联
Makefile文件内容如下:
obj-$(CONFIG_ADD_SUB)+=add_sub.o
obj-$(CONFIG_TEST)+=test.o
Kconfig文件内容如下:
#
# add_sub configuration
#
menu "ADD_SUB"
comment "ADD_SUB"
config CONFIG_ADD_SUB
tristate "ADD_SUB support"
default y
config CONFIG_TEST
tristate "ADD_SUB test support"
depends on CONFIG_ADD_SUB
default y
endmenu
然后修改上层的Kconfig文件,添加如下内容:
Source "drivers/add_sub_Kconfig/Kconfig"
然后修改上层的Makefile文件,添加如下内容:
obj-$(ADD_SUB) += add_sub_Kconfig/
就可以在主目录下执行make menuconfig后,在驱动下找到对应的驱动和编译信息了
- EasyStack郭长波连任OpenStack基金会独立董事
- VMware Fusion 中如何复制centos/linux虚拟机
- 浅谈国外航空发动机大数据应用
- asp.net mvc SelectList 的selected 失效及解决方案
- 类极客公园火箭发射“返回顶部”jQuery效果(WordPress代码教程)
- 利用ganymed-ssh2远程执行其它Linux机器上的shell命令
- 浅析软件开发的3个层次
- MSBUILD 命令行编译的时候请注意msbuild文件名称或路经中空格导致出错
- Python可以用来做什么?
- 使用View Model从表现层分离领域模型
- 代码实现WordPress点击进入随机一篇文章的方法
- UE4新手编程之创建空白关卡和添加碰撞体
- Office Web Apps
- hadoop: hive 1.2.0 在mac机上的安装与配置
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 踩坑了,JDK8 中 HashMap 依然会产生死循环问题!
- 使用shell-operator实现Operator
- 教你用Python 操作 PDF 的几种方法
- 如何在K8s上设置生产级的EFK?(上)
- IntelliJ IDEA 构建 Maven 多模块工程项目
- GDP越高就越幸福吗?用Python分析《世界幸福指数报告》后我们发现…
- 图解:什么是哈希?
- 【Python基础】一文看懂 Pandas 中的透视表
- 彻底干掉恶心的 SQL 注入漏洞, 一网打尽!
- 某小型公司持续集成工具 Jenkins 实践
- 使用RBAC Impersonation简化Kubernetes资源访问控制
- 求求你别再用 MySQL offset 和 limit 分页了?
- 短视频带货源码,获取购物车中所有商品列表并加载显示
- 【Flutter 实战】菜单(Menu)功能
- 【Flutter 实战】路由堆栈详解