Linux驱动程序编写&&应用程序对她的调用

这就是一个最简单的驱动程序,编译之后,我们可以把生成的hello.ko文件拷到开发板上,分别执行如下命令:

insmod hello.ko#加载模块,会调用hello_init()#

rmmod hello#移除模块,会调用hello_exit()#

下面,我将以一个S5PV210的led驱动程序为例,一步一步叫大家编写一个属于自己的驱动程序,并学会使用它:

目的:将开发板上的led灯(以一个灯为例,其他的一样)作为一个设备,为其编写驱动程序,并调用!

准备工作:①、硬件结构:led1(GPJ0_3)②、内核:kernel,可以在www.kernel.org下载

一、编译好我们自己的内核

以我自己的kernel.tar.gz为例:

①、tar -xvzf kernel.tar.gz #将内核源码解压到当前目录#

②、cd ./kernel #解压完后,进入kernel根目录#

③、cp ./arch/arm/configs/XXX_deconfig.config .config #从arch/arm/configs/目录下拷贝一个配置文件到kernel根目录,重命名为.config#

④、make zImage#编译生成内核镜像文件(大约20分钟左右)#

OK,一切顺利的话,我们就得到了一个我们自己编译好的内核zImage

二、有了内核之后,我们就可以开始写我们的驱动程序了(如果上一步没有成功,并不是说我们不能写代码,只是我们的驱动程序是为内核服务的,我们必须为她指定一个内核,他才能编译过去)

①、首先我们需要为设备(也就是我们的led灯)分配设备号(包括这设备号、从设备号),我们一般采用动态分配法:

dev_t led_device_num;

alloc_chrdev_region(&led_device_num, 0, 1, "led_dev"); #动态分配设备号#

②、有了设备号之后,我们就可以找到相应的设备,并对这个设备进行我们想要的操作了!永远不要忘记:在Linux的眼中,一切都是文件!对于文件来说,最常用的操作不外乎:open,read,write,seek,close等!因此,我们也应该提供类似的函数对设备进行操作,供应用程序使用,而不应该自己随便写个函数实现功能!

在./include/linux/fs.h文件中定义了一个结构体——file_operations,这是一个非常重要的结构体,我们编写驱动程序的时候,无非是对这个结构体中定义的一些函数的实现。如:

static struct file_operations led_dev_fops ={.read=led_dev_read,.write=led_dev_write,.open=led_dev_open,.owner= THIS_MODULE};

led_dev_read,led_dev_write,led_dev_open分别是对read,write,open函数指针的的初始化,以后,当应用程序对led设备(我们现在编写的)进行open、read、write操作时,就会分别调用“=”后面的函数,当然,我们会在后面实现这几个函数。

可是,我们只是定义了一个结构体变量、并进行了初始化啊,设备怎么知道呢,内核又怎么把系统的函数与我们自己实现的函数联系起来呢?所以,我们还应该把这种函数对应关系告诉我们的设备:

static struct cdev led_dev;#定义一个字符型设备变量#

cdev_init (&led_dev, &led_dev_fops);#初始化该字符设备,主要是对函数指针的初始化#

③、字符设备最终是由内核调用的,前面的工作都还只是闭门造车,现在车造好了,该上路了,是不是需要得到交通部门的许可呢?同样,我们应该告诉内核,我们需要注册这样一个设备:

cdev_add (&led_dev, led_dev_num, 1);#注册该设备#

④、完成上述步骤后,我们的初始化工作(即:获取设备号、注册设备)已经做好,接着我们就要编写我们自己的文件操作函数了,即:led_dev_open、led_dev_read、led_dev_write。

⑤、后续处理。做好这些之后,我们需要在卸载模块时,释放我们申请的设备号、并卸载该设备:

cdev_del (&led_dev);#卸载设备#unregister_chrdev_region(led_dev_num, 1);#释放设备号#

附上一段我自己编写的代码:

原来和文字沾上边的孩子从来都是不快乐的,

Linux驱动程序编写&&应用程序对她的调用

相关文章:

你感兴趣的文章:

标签云: