牛刀小试驱动_hello.ko

Linux驱动开发 实践1

将hello.c驱动移植到micro2440开发板运行


//Hello.c

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

//模块申明 
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
	printk("<0> Hello, world\n");		//类似于printf函数
	return 0;
}
static void hello_exit(void)
{
	printk("<0> Goodbye, cruel world\n");
}
// module_init  module_exit 都是宏定义
module_init(hello_init);		//模块装载  相当于 main函数的作用
module_exit(hello_exit);		//模块卸载  

printk是在内核中运行的向控制台输出显示的函数,printk函数中可以使用附加不同的日志级别或消息优先级。

用printk,内核会根据日志级别,可能把消息打印到当前控制台上,这个控制台通常是一个字符模式的终端、一个串口打印机或是一个并口打印机。这些消息正常输出的前提是──日志输出级别小于console_loglevel(在内核中数字越小优先级越高)。

没有指定日志级别的printk语句默认采用的级别是 DEFAULT_ MESSAGE_LOGLEVEL(这个默认级别一般为<4>,即与KERN_WARNING在一个级别上),其定义在linux26/kernel/printk.c中可以找到。

日志级别一共有8个级别,printk的日志级别定义如下(在include/linux/kernel.h中):

#define KERN_EMERG 0

#define KERN_ALERT 1

#define KERN_CRIT 2

#define KERN_ERR 3

#define KERN_WARNING 4

#define KERN_NOTICE 5

#define KERN_INFO 6

#define KERN_DEBUG 7

本例子使用的最高级别0,如果用其他数值,可能在控制台显示不出打印信息。


//Makefile

//red hat

obj-m := hello.o	//与c文件对应
#这个路径根据你主机上的linux内核版本及路径而定
#build是个符号链接,其实际指向内核源文件的路径

KERNELDIR := /lib/modules/2.6.18-194.el5/build
PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
	rm -f *.o *.ko *.mod.c *.markers *.symvers

//arm

obj-m := hello.o		//与c文件对应
CC = arm-linux-gcc		//指定交叉编译工具  默认 gcc

#这个路径根据你主机上的linux内核版本及路径而定
#build是个符号链接,其实际指向内核源文件的路径

#KERNELDIR := /lib/modules/2.6.18-194.el5/build
KERNELDIR := /root/Micro2440/linux-2.6.29    //需要跟开发板内核版本一致
PWD := $(shell pwd)
modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
	rm -f *.o *.ko *.mod.c *.markers *.symvers

----------------------------------------------------------------------------------------------------------------------------

测试:

Red hat 5.5

Insmod hello.ko        //加载驱动

lsmod                          //查看当前加载的驱动

rmmod hello              //卸载驱动

 

Micro2440 使用的是linux-2.6.29的内核版本,所以编译时需要与开发板内核版本一致

NFS挂载到开发板上运行时,能正常挂载,但是发现卸载不了。

[root@FriendlyARM module]# rmmod hello

rmmod: chdir(2.6.29.4-FriendlyARM): No suchfile or directory

 

解决方法是:创建 /lib/modlues/2.6.29.4-FriendlyARM 目录

能成功卸载了,出现rmmod: module 'hello' not found 不影响,应该是busybox的问题。

 

模块参数

在用户态下编程可以通过main()来传递命令行参数,而编写一个内核模块则可通过module_param()来传递命令行参数。module_param宏是Linux 2.6内核中新增的。相关的宏主要有:

                   module_param(name,type, perm);
                  module_param_named(name,value, type, perm)

模块参数的类型(即type)有以下几种:

bool

invbool :一个布尔型( true 或者 false)值(相关的变量应当是 int 类型). invbool 类型颠倒了值, 所以真值变成 false,反之亦然.

charp :一个字符指针值. 内存为用户提供的字串分配,指针因此设置.

int

long

short

uint

ulong

ushort

module_param使用了3个参数:变量名,它的类型,以及一个权限掩码用来做一个辅助的sysfs入口。

 

通过宏module_param指定保存模块参数的变量。模块参数

用于在加载模块时传递参数给模块。

module_param(name, type, perm)

name:变量的名称

type:变量类型,bool:布尔型 int:整型 charp:字符串型

perm是访问权限。 S_IRUGO:读权限 S_IWUSR:写权限

例:

int a = 3;

char *st;

module_param(a,int, S_IRUGO);

module_param(st,charp, S_IRUGO);

 

说白了就是传递参数而已,直接上代码

//hello.c

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

MODULE_LICENSE("Dual BSD/GPL");

static char *whom = "world";
static int howmany = 1;

static int hello_init(void)
{
	int i=0;
	for(i = 0;i < howmany;i++)
	{
		printk("<0>%d:Hello, %s!\n",i+1,whom);
	}
	return 0;
}

static void hello_exit(void)
{
	printk("<0>Goodbye, cruel world!\n");
}
module_init(hello_init);
module_exit(hello_exit);

module_param(howmany, int, S_IRUGO);	
module_param(whom, charp, S_IRUGO);	

insmod hello_param.ko howmany=3 whom=”test”   //特别注意 =号两边不要留空格


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值