驱动之hello world

很多人一听到驱动就有种很高深的感觉,为什么装个驱动我的摄像头就有图像了呢,为什么装个操作系统后要装那么多的驱动呢。

这里我们一步一步的来了解下linux下的驱动。

学过编程语言的第一个接触的必定是一个叫“hello world”的东东。这里我们也来弄一个“hello world”。

在真正的写驱动之前我们先了解下linux内核,linux内核采用的是模块化编程,这样可以很容易的添加或删除一个功能,同时可以在内核运行的过程中可以动态的添加功能,这部分功能的代码被称为”模块“,我们写的驱动程序就是一个模块,但模块不仅仅局限于驱动,文件系统、网络……,都可以是模块。我们在真正的写驱动之前我们先需要了解模块的结构。

一、模块的编写

linux驱动是C语言编写的,就如我们写C语言的应用程序必须要有一个叫做“main”的函数,我们也模块的时候也有些类似的东西。

下面我们就来了解下模块。模块的组成中有些是必须的,有些是可选的我们先看下这些必须的,也就是一个模块最基本的组成,下面便是一个最基本的模块:

#include <linux/module.h>
                    #include <linux/kernel.h>
                    #include <linux/init.h>
                    MODULE_LICENSE ("GPL");
                    static int __init hello_2_init (void)
                    {
                             printk (KERN_INFO "Hello world\n");
                             return 0;
                    }
                    static void __exit hello_2_exit (void)
                    {
                             printk (KERN_INFO "Goodbye world\n");
                    }
                    module_init (hello_2_init);
                 module_exit (hello_2_exit);

这个模块的代码可以分为四部分:

1、头文件
        #include <linux/module.h>
                    #include <linux/kernel.h>
                  #include <linux/init.h>

这些头文件是一个模块最基本的头文件,我们写一个模块的时候需要毫无理由的加这几个头文件,这几个头文件中有我们模块中最基本的一些符号的定义,所谓的符号就是一些结构体、宏等的定义。

2、许可证的申明

MODULE_LICENSE ("GPL");

我们在写模块的时候,一般都会申明许可证用来说明我们遵循"GPL"协议。Linux内核识别的许可证有“GPL”——任意版本的GNU通用公共许可证、“GPL v2”——GPL第二版、“GPL and additional rignts”——GPL及附加权利、“Dual BSD/GPL”——BSD/GPL双许可证和“Proprietary”——专有。

虽然许可证的申明没有严格的要求,但一般我们在写驱动的时候至少会选择一个"GPL",因为如果没有许可证的申明的话,那么这个模块就是一个专有的模块,而Linux本身遵循GPL,所以不愿意非GPL的模块加入内核。一个专有模块加入内核的时候,内核会认为内核被污染了而产生抱怨,如下:

[90518.655714] hello: module license 'unspecified' taints kernel.
                 [90518.657320] Disabling lock debugging due to kernel taint

3、加载函数
        static int __init hello_2_init (void)
                    {
                    printk (KERN_INFO "Hello world\n");
                    return 0;
                    }
                 module_init (hello_2_init);

加载函数又叫初始化函数,是向内核添加模块的时候被执行的。

4、卸载函数

static void __exit hello_2_exit (void)
                    {
                    printk (KERN_INFO "Goodbye world\n");
                    }
                  module_exit (hello_2_exit);

卸载函数又叫清除函数,是从内核中删除一个模块的时候被执行的。

上面的四部分是一个模块中最基本的组成,有了这四部分我们就可以说这是一个模块了。

二、模块的编译

有了代码了,而代码在执行前必须先编译。和编译应用程序不同,编译模块必须依赖一个配置并且编译过的内核源码树。因为Linux内核支持多平台,所以在使用之前必须先配置,而我们编译模块必然依赖一个和我们目标平台相同的内核源码树。怎么才能使用这个内核源码树编译我们的模块呢,这个在内核中有明确的说明,可以参考Linux内核目录下Documentation/kbuild/modules.txt,按照说明我们写一个Makefile,如下:

ifeq ($(KERNELRELEASE),)
                    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
                    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 Module* modules*
                    .PHONY: modules modules_install clean
                    else
                             obj-m := hello.o
                  endif

这个Makefile是一个通用的编译模块的Makefile,在终端输入make

make -C /lib/modules/2.6.35-22-generic/build M=/home/linux/ex2-init-exit modules                 M=/home/linux/ex2-init-exit modules
                    make[1]: Entering directory `/usr/src/linux-headers-2.6.35-22-generic'
                    LD      /home/linux/ex2-init-exit/built-in.o
                    CC [M]  /home/linux/ex2-init-exit/hello.o
                    Building modules, stage 2.
                             MODPOST 1 modules
                             CC      /home/linux/ex2-init-exit/hello.mod.o
                             LD [M]  /home/linux/ex2-init-exit/hello.ko
                    make[1]: Nothing to be done for `modules'.
                  make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-22-generic'

通过编译就会生成一个.ko的文件,这就是我们的模块了。

三、模块的加载和卸载

我们在终端输入:
                    insmod hello.ko
                    和
        rmmod hello.ko
                    然后用dmesg查看,就能看到我们在加载函数和卸载函数里打印的内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值