如何编写Linux 驱动程序

如何编写Linux 驱动程序,第1张

以装载和卸载模块为例:

1、首先输入代码

#include <linux/init.h>

#include <linux/module.h>

2、然后输入下方的代码:

static int my_init(void)

{

                    return  0

}

static void my_exit(void)

3、然后在输入下方的代码:

{

                    return

}

module_init(my_init)

module_exit(my_exit)这样就完成了。

该文重点给出了三个实例来讲解Linux驱动,使新手快速、从代码层了解什么是Linux设备驱动。

本文算是笔记,大体上是翻译该文的前两部分,即前两个实例,这两个例子都可能正确成功运行。

文件: Writing device drivers in Linux.pdf

大小: 216KB

下载: 下载

所需知识

- C 语言编程

- 微处理器编程.对处理器的工作原理有一定的了解,如内存管理、中断等

用户空间内核空间

写设备驱动时,了解“用户空间”和“内核空间”之间的区别是非常重要的。

- 内核空间。Linux内核简单并高效地管理着机器的硬件,为用户提供简单并

规范的编程接口。同样地,内核,特别是内核中的驱动,是用户/程序员与硬

件之间的桥梁或接口。内核的任何例程或函数(比如模块、驱动)都属于内核

空间。

- 用户空间。用户程序,比如unix shell或其他的gui应用程序(比如

kpresenter),都属于用户空间。显然,这些应用程序都要与硬件打交道。但是

它们不并直接 *** 作硬件,而是通过内核提供的函数来实现。

用户空间与内核空间之间的接口函数

内核为用户空间提供了一系列的例程或函数,用户的应用程序利用这些接口来与硬件交互

。通常,在UNIX或Linux系统中,这种对话是通过函数或子程序来读写文件的。原因是从

用户的角度来看,UNIX设备就是文件。

另一方面,在内核空间中Linux也提供了一系列的函数或子程序来完成底层与硬件的交互

,并允许从内核向用户空间传递信息。

通常,每个用户空间的(设备或文件允许使用的)函数,都能在内核空间中找到一个类似

的函数,(允许信息从内核传递给用户空间,反之亦然)

内核空间与硬件设备之间的接口函数

内核空间中有许多函数用于控制硬件或在内核与硬件之间交互信息。

第一个驱动:在用户空间加载和移除驱动

现在将展示如何完成第一个驱动,在内核中将看作模块

新建一个文件nothing.c如下

include

MODULE_LICENSE(“Dual BSD/GPL”)

2.6.x版本后的内核,编译模块会略微复杂一点。首先,需要有一份完整的、编译过的内

核源码树。在下面的文字中,将假设使用2。6。8版本的内核。

其次,需要一个makefile文件,本例中的makefile文件名为Makefile,内容如下:

obj-m := nothing.o

与之前版本的内核不同,现在编译模块时使用的内核需要与模块将要加载的内核相同。

编译上面的文件,可以使用命令:

make -C /usr/src/kernel-source-2.6.8 M=pwd modules

这个极其简单的模块就属于内核空间,一旦其被加载,它就是内核空间的一部分。

在用户空间,可以使用下面的命令加载它,需要root权限:

insmod nothing.ko

insmod 这个命令用于为内核加载模块。尽管现在我们已经加载了nothing.ko这个模块,

但是这个模块毕竟没有任何用处。

可以通过查看系统里已加载的模块来检查是否已经成功加载了nothing.ko

lsmod

最后,需要卸载该模块时使用下面的命令:

rmmod nothing

重新使用lsmod,可以发现nothing模块已经不在了。

“Hello world”驱动:在内核空间加载和移除驱动

当一个模块设备驱动加载到内核,将执行一些初始的工作,如重新设置设备,reserving

RAM, reserving interrupts, reserving input/output ports, etc.

这些工作得以在内核空间执行,必须要有两个函数存在:module_init 和

module_exit它们对应于用户空间的insmod和rmmod命令。总之,用户命令insmod和

rmmod使用了内核空间的函数module_init和module_exit.

来看一个经典的程序 HELLO WORLD:

//hello.c#include #include #inlucde MODULE_LICENSE("Dual BSD/GPL")static int hello_init(void)

{

printk("<1>Hello world!\n") return 0

}static void hello_exit(void)

{

printk("<1>Bye, cruel world!\n")

}

module_init(hello_init)

module_exit(hello_exit)1234567891011121314151617181920

其中hello_init 和 hello_exit 函数可以取任意名,但为了加载和移除功能是更容易识

别,它们作为参数传递给函数module_init 和 module_exit.

printk函数与printf函数非常类似,但printk只工作在内核中。<1>表示打印信息

为最高优先级(数字越低,优先级越高)。这样,不仅可以在内核系统日志中看到该

打印信息,还能在系统控制台接收到该打印信息。

可以用之前的命令来编译这个模块,此时只需要将模块名加入到Makefile文件中即可:

obj-m := nothing.o hello.o

本文的其他部分,将Makefile作为给读者的练习。一个完整的Makefile文件可以编译

本教程中的所有示例模块。

当模块被加载或卸载时,通过printk打印的信息将会出现在系统控制台。如果打印

信息没有出现在终端里,则可通过dmesg命令或查看系统日志文件(cat

var/log/syslog)看到打印信息。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/7580784.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-07
下一篇2023-04-07

发表评论

登录后才能评论

评论列表(0条)

    保存