驱动开发1 概念、内核模块编程、内核消息打印函数printk函数的使用、内核模块传参、内核导出符号

1 驱动相关概念

2 内核模块编程

内核模块编写实例代码+注释

#include <linux/init.h>
#include <linux/module.h>

//入口函数,安装内核模块时执行
static int __init mycdev_init(void)
{
    //static 修饰当前函数只能在本文件使用
    //int 函数的返回值类型,如果函数规定返回值但是没有加返回值,编译会报错
    //mycdev_init函数名,可以自己起名字
    //void表示函数无参数,当没有参数时void一定要加,不然报错
    //__init的作用是用来告诉编译器当前代码保存在.init.text段中
    //#define __init        __section(".init.text")  
    //linux内核也会有自己的链接脚本  vmlinux.lds,这个链接脚本里规定了不同的内容在
    //内存中的什么位置
    return 0;
}
//出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{
    //#define __exit        __section(".exit.text")
    //__exit指定出口函数保存在.exit.text段中

}
//用于声明入口函数
module_init(mycdev_init);
//用于声明出口函数
module_exit(mycdev_exit);
//声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

内核模块编译(外部编译Makefile)

#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
#KERBELDIR保存开发板内核源码路径
#KERNELDIR := /home/ubuntu/linux-5.10.61/
#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除
    make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m :=  demo.o

通用版本的Makefile

modname ?= demo
arch ?= arm
ifeq ($(arch),arm)  #通过命令行传过来的架构决定怎么编译
#KERBELDIR保存开发板内核源码路径
KERNELDIR := /home/ubuntu/linux-5.10.61/
else
#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif

#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除
    make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m :=  $(modname).o

3 内核消息打印函数printk函数的使用

代码示例

#include <linux/init.h>
#include <linux/module.h>

// 入口函数,安装内核模块时执行
static int __init mycdev_init(void)
{
    // static 修饰当前函数只能在本文件使用
    // int 函数的返回值类型,如果函数规定返回值但是没有加返回值,编译会报错
    // mycdev_init函数名,可以自己起名字
    // void表示函数无参数,当没有参数时void一定要加,不然报错
    //__init的作用是用来告诉编译器当前代码保存在.init.text段中
    // #define __init       __section(".init.text")
    // linux内核也会有自己的链接脚本  vmlinux.lds,这个链接脚本里规定了不同的内容在
    // 内存中的什么位置
    printk(KERN_ERR "hello world\n");
    int a=10;
    printk(KERN_ERR "%d\n",a);
    return 0;
}
// 出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{
    // #define __exit       __section(".exit.text")
    //__exit指定出口函数保存在.exit.text段中
}
// 用于声明入口函数
module_init(mycdev_init);
// 用于声明出口函数
module_exit(mycdev_exit);
// 声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

4 内核模块传参

#include <linux/init.h>
#include <linux/module.h>
int a=10;
module_param(a,int,0664);//声明变量a可以进行命令行传参
MODULE_PARM_DESC(a,"this is a int value");//添加要传参的变量描述
static int __init mycdev_init(void)
{
    printk("a=%d\n",a);
    return 0;
}
static void __exit mycdev_exit(void)
{


}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

5 内核导出符号

1 定义demo1.c,demo1.c中完成函数的定义

#include <linux/init.h>
#include <linux/module.h>
int add(int i,int j)
{
    return i+j;
}
//生成add的符号表文件
EXPORT_SYMBOL(add);
static int __init mycdev_init(void)
{
    
    return 0;
}
static void __exit mycdev_exit(void)
{


}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

2 创建demo2.c,里面完成demo1.c里面函数的调用

#include <linux/init.h>
#include <linux/module.h>

extern int add(int i,int j);
static int __init mycdev_init(void)
{
    printk("调用模块1函数执行结果为:%d",add(3,5));
    return 0;
}
static void __exit mycdev_exit(void)
{


}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值