65.最简单的linux驱动框架--hello word

 

 

驱动开发环境搭建好了,下面就可以开发驱动了,但是怎么开始第一个驱动呢,我们开发其他软件的时候都是习惯先编写个hello world,这个驱动我们也从这个开始最简单的驱动  开始,开启驱动的大门。

编译驱动前提,内核预先编译好。

一. 编写驱动代码
      1,用什么工具去写---source insight(看代码的工具)       

新建工程的方法不多说,环境搭建部分我们已经说明。
       2,怎么写
                在souceinsght去写?
                驱动的编写是有规则的,记住规则套用就可以了。
                驱动代码需要有四个部分
                  hello_world.c

/*******************************
	1,头文件
	2,驱动模块装载和卸载函数入口到声明
	3,实现模块装载和卸载函数入口
	4,GPL声明
********************************/
#include 
#include 


static int __init hello_drv_init(void)
{
	//一般做系统资源申请
    printk("-------%s-------------\n", __FUNCTION__);
    return 0;
}
static void __exit hello_drv_exit(void)
{
	//一般做释放系统资源
    printk("-------%s-------------\n", __FUNCTION__);
}

module_init(hello_drv_init);
module_exit(hello_drv_exit);

MODULE_LICENSE("GPL");

二 .编译驱动代码--Makefile (.ko)

编写makefile文件:(当前的makefile实际上被读取两次)

 

ROOTFS_DIR =  /nfs/rootfs    //选择自己的根文件系统路径

ifeq ($(KERNELRELEASE), )
//内核源码到路径,不同环境会不一样,内核源码一定要先编译
KERNEL_DIR = /home/george/Linux_4412/kernel/linux-3.14
CUR_DIR = $(shell pwd)

all :
	make -C  $(KERNEL_DIR) M=$(CUR_DIR) modules

clean :
	make -C  $(KERNEL_DIR) M=$(CUR_DIR) clean
	
install:
	cp -raf *.ko   $(ROOTFS_DIR)/drv_module //把Ko放到我们的根文件系统中


else
//用于指定到底编译哪个代码--hello.c
obj-m += hello_world.o


endif

 

65.最简单的linux驱动框架--hello word_第1张图片

三. 装载和卸载驱动

开发板上电,通过串口进行打印信息查看,此时已经通过tftp加载了最新的内核

加载内核:

65.最简单的linux驱动框架--hello word_第2张图片

但是出现了报错,百度说是加载的和编译的内核版本不一致导致的。

查看了一下开发板的内核

确实不对,重新编译下内核,和设备树,拷贝到/tftpboot/目录下。

65.最简单的linux驱动框架--hello word_第3张图片

然后就可以正常加载了。

65.最简单的linux驱动框架--hello word_第4张图片

           卸载也没什么问题了。

 

四.参数传递

    加载ko:  insmod hello.ko myname="george" myvalue=33

    用途: wifi驱动,wifi硬件中内部也运行内部代码,原厂开发,这些代码叫做固件--firmware.bin
          装载wifi驱动,必须告诉固件到文件在哪里
             insmod  rtxxx.ko path=/lib/modules/firmware/xxx.bin

    在代码如何处理参数:
    module_param(name, type, perm)
    参数1:表示参数到名字,比如myname, myvalue
    参数2:参数到类型, charp, int
    参数3: /sys/modules/表示文件到权限: 0666

    用法:
        module_param(myvalue, int, 0666);
        module_param(myname, charp, S_IRUGO|S_IWUGO|S_IXUGO);

/*******************************
	1,头文件
	2,驱动模块装载和卸载函数入口到声明
	3,实现模块装载和卸载函数入口
	4,GPL声明
********************************/
#include 
#include 

static int myvalue = 56;
static char *myname = "li";

static int __init hello_drv_init(void)
{
	//一般做系统资源申请
	printk("-------%s-------------\n", __FUNCTION__);
	printk("name =%s,value=%d\n",myname,myvalue);
    return 0;
}
static void __exit hello_drv_exit(void)
{
	//一般做释放系统资源
	printk("-------%s-------------\n", __FUNCTION__);
}

module_init(hello_drv_init);
module_exit(hello_drv_exit);

MODULE_LICENSE("GPL");

module_param(myvalue,int,0644);
module_param(myname, charp, 0644);

65.最简单的linux驱动框架--hello word_第5张图片

五.符号导出

模块化设计,自己写好的代码按功能单独封装在一个KO里面,EXPORT_SYMBOL之后就将函数放到了全局符号表(一个链式结构),内核可以找到相应的函数。其他模块可以调用它实现代码的共用。有点类似于动态库。

#include 
#include 

//不需要模块加载和卸载到入口声明,直接定义好一些封装的函数

int my_add(int a, int b)
{
	return a+b;
}

EXPORT_SYMBOL(my_add);

int my_sub(int a, int b)
{
	return a-b;
}

EXPORT_SYMBOL(my_sub);

MODULE_LICENSE("GPL");
#include 
#include 
#include 

#include "math.h"


static int myvalue = 56;
static char *myname = "peter";

static int __init hello_drv_init(void)
{

	//一般做系统申请资源
	printk("-------%s-------------\n", __FUNCTION__);
	printk("name = %s, value = %d\n", myname, myvalue);


	printk("a+b = %d, a-b = %d\n", my_add(33,22), my_sub(44,22));
	
	return 0;
}

static void __exit hello_drv_exit(void)
{
	//一般做系统释放资源
	printk("-------%s-------------\n", __FUNCTION__);

}


module_init(hello_drv_init);
module_exit(hello_drv_exit);

MODULE_LICENSE("GPL");
module_param(myvalue, int, 0644);
module_param(myname, charp, S_IRUGO|S_IWUSR);

math.h 


#ifndef __MATH_H__
#define __MATH_H__


int my_add(int a, int b);
int my_sub(int a, int b);

#endif

编译好ko文件后,设备进行加载

65.最简单的linux驱动框架--hello word_第6张图片

出现了报错。。

原因是math.ko还没有在内核中,先insmod math.ko进行装载,然后ls /sys/module/进行查看,此时math已经有了

再进行hello world的装载就成功了。

65.最简单的linux驱动框架--hello word_第7张图片

你可能感兴趣的:(#,linux--驱动开发,#,华清嵌入式培训,linux最简单驱动)