驱动模块

一、 驱动程序相关shell命令

1、insmod [选项] [驱动模块]
功能:将驱动程序加载到Linux内核中添加新用户
2、rmmod  [选项] [驱动模块]
功能:将驱动程序从Linux内核删除
3、lsmod  [驱动模块]
功能:查看内核存在哪些模块。本质是读取/proc/moduls文件
4、modinfo [选项] [驱动模块]
功能:用来查看模块信息、包含功能、作者信息等
5、dmesg [选项]    
选项中  [-c]   清空打印日志信息
功能:查看printk函数打印信息

二、驱动程序框架

1、驱动程序(不管字符设备、块设备、网络设备)的框架必须包含如下三部分:
(1)、MODULE_LICENSE(“Dual BSD/GPL”);
表示源码开发,不用于商业用途。如不包含会打印如下信息:

	module license 'unspecified' taints kernel

(2)、module_init(parame);
parame:实现什么驱动功能的函数名
驱动加载函数(宏),ismod命令会调用驱动程序module_init()。一般为驱动入口
(3)、module_exit(parame);
parame:退出什么驱动功能的函数名
驱动卸载函数(宏),rmmod命令会调用驱动程序module_exit()。一般为驱动出口

非必须组成部分:
MODULE_AUTHOR (author); —声明模块的作者
MODULE_DESCRIPTION (description); —声明模块的描述
MODULE_VERSION (version_string); —声明模块的版本
MODULE_DEVICE_TABLE (table_info); —声明模块的设备表
MODULE_ALIAS (alternate_name); —声明模块的别名

hello.c

#include <linux/init.h> 
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");

static int __init hello_init(void)   //必须为 int __init  xxxx(void)
{
	int temp = 666;
	printk(KERN_WARNING "hello_init  %d \n",temp);
	return temp;
}
static void __exit hello_exit(void) //必须为 void __exit xxxx(void)
{
	printk(KERN_ALERT "hello_exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
非必须
MODULE_AUTHOR("Y__Can");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("hello_world");

Makefile

ifneq ($(KERNELRELEASE),)
obj-m := hello.o    #把对应 .c 文件改为 .o
else
KERNELDIR ?= /imx/linux-2.6.35.3#用于开发板
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build # 用于虚拟机编译  路径为已编译过内核下的路径
PWD := $(shell pwd)
 
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order

如果我们想由两个源文件(比如file1.c和file2.c )构造出一个名称为module.ko的模块, 则正确的makefile可如下编写:
obj-m := module.o
module-objs := file1.o file2.o
要点说明:
1、文件名字必须为Makefile
2、KERNELRELEASE 是在内核源码的顶层Makefile中定义的一个变量,内核发行的版本号
3、$(obj-m)表示对象文件(object files)编译成可加载的内核模块。
流程说明:
1、第一次进入Makefile,KERNELRELEASE没有被定义
2、执行else后面的语句,给KERNELDIR, PWD赋值
3、执行default,编译
3.1、Make -C选项进入内核源代码目录,找到顶层的Makefile
3.2、M=PWD,返回当前目录执行Makefile文件
3.3、这就是第二次进入这个Makefile,在这次,由于KERNELRELEASE变量已经定义,因此不需要进入else语言,在这里,obj-m:=hello.o,在这里内核会帮你处理一切,这句话是告诉内核,需要从hello.o创建一个驱动模型(module)模块参数

2、驱动模块参数

module_param (参数名,参数类型,参数读/写权限) 
static char *whom = "world";
static int howmany = 1; 
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IWUSR ); 
内核支持的模块参数类型包括:
byte、short、ushort、int、uint、long、ulong、charp(字符指针)、bool以‘u’开头的为无符号值。
参数3#define S_IRWXU 00700 用户对该文件具有读,写,和执行权限
#define S_IRUSR 00400  用户对该文件具有读权限
#define S_IWUSR 00200 用户对该文件具有写权限
#define S_IXUSR 00100  用户对该文件具有执行权限

#define S_IRWXG 00070 用户组里的所用用户对该文件具有读,写,和执行权限
#define S_IRGRP 00040  用户组里的所有用户对该文件具有读权限
#define S_IWGRP 00020  用户组里的所有用户对该文件具有写权限
#define S_IXGRP 00010   用户组里的所有用户对该文件具有执行权限

#define S_IRWXO 00007  其他用户对该文件具有读,写,和执行权限
#define S_IROTH 00004   其他用户对该文件具有读权限
#define S_IWOTH 00002   其他用户对该文件具有写权限
#define S_IXOTH 00001    其他用户对该文件具有执行权限

#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) 表示只可以读,不可以写
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) 表示可以写
$ insmod mydriver.ko  whom="Student" howmany = 5//可使对应变量值发生改变
$echo x > howmany  //修改运行后的值  

3、驱动模块数组

module_param_array(数组名,数组类型,数组长,参数读/写权限)
static int int_array[6];  
int narr; 
module_param_array(int_array, int, &narr, 0644);
$insmod hello.ko int_array=128,256,512 

4、驱动模块函数

EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);  //_GPL 版本的宏定义的导出符号只能对 GPL 许可的模块可用
int add_integar(int a, int b)
{
	return a+b;
}
int sub_integar(int a, int b)
{
	return a-b;
}
EXPORT_SYMBOL(add_integar);  //EXPORT  才可以在别的模块中调用
EXPORT_SYMBOL(sub_integar);
Makefile加上
KBUILD_EXTRA_SYMBOLS+=/home/lyc/imx/work/1/Module.symvers      //路径为驱动.c下生成的Module.symvers
export KBUILD_EXTRA_SYMBOLS
调用者需要extern int add_integar(int a,int b);
# cat /proc/kallsyms | grep integar  //查看可以调用的函数

https://imgconvert.csdnimg.cn/aHR0cHM6Ly9hdmF0YXIuY3Nkbi5uZXQvNy83L0IvMV9yYWxmX2h4MTYzY29tLmpwZw
源文件:
hello.c

#include <linux/init.h> 
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
MODULE_LICENSE("Dual BSD/GPL");

//模块参数
static char *whom = "world";
static int howmany = 1;
module_param(howmany,int,S_IRUGO);
module_param(whom,charp,S_IWUSR);

//模块数组
static int int_array[6] = {0};  
int narr; 
module_param_array(int_array, int, &narr, 0644);

//模块函数
int add_integar(int a, int b)
{
	return a+b;
}
int sub_integar(int a, int b)
{
	return a-b;
}
EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(sub_integar);

static int __init hello_init(void)   //必须为 int __init  xxxx(void)
{
	int temp = 666;
	printk(KERN_WARNING "hello_init  %d %d %s \n",temp,howmany,whom);	
	printk("int_arr[0]=%d,int_arr[1]=%d\n",int_array[0],int_array[1]);
	printk("narr=%d\n",narr);
	return temp;
}
static void __exit hello_exit(void) //必须为 void __exit xxxx(void)
{
	printk(KERN_ALERT "hello_exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
非必须
MODULE_AUTHOR("Y__Can");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("hello_world");

hello1.c

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

MODULE_LICENSE("Dual BSD/GPL");

extern int add_integar(int a, int b);
extern int sub_integar(int a, int b);

static int __init hello_init(void)   //必须为 int __init  xxxx(void)
{
	printk("add_int=%d\n",add_integar(1,2));
	printk("sub_int=%d\n",sub_integar(1,2));
	return 0;
}

static void __exit hello_exit(void) //必须为 void __exit xxxx(void)
{
	printk(KERN_ALERT "hello_exit\n");
}

module_init(hello_init);
module_exit(hello_exit);

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值