驱动程序分层分离概念___总线设备驱动模型

在输入子系统那一章,一个驱动分为上下两层,现在我们要引入另外一个概念,叫做分层分离概念:

在输入子系统,Input.c中中提供统一的接口,buttons.c专注于硬件相关的代码,evdev.c则专注于纯软件的东西,现在我们把这两个分离出来,Input.c与下面一层分层,

//现在我们来看一下我们写输入子系统说的一个例子,gpio_keys.c

为什么我们会关心probe函数,现在我们来引入另外一个概念:

总线BUS--驱动driver - 设备device模型

device:放硬件相关的东西

driver:放比较稳定的代码

现在我们好奇这个模型怎么用呢:

我们查看一个这个函数:platform_driver_register(&gpio_keys_device_driver);


意思为向上通过一条虚拟总线driver_register(drv->driver)注册一个driver

这个driver_register会将这个驱动结构体放到Bus的某个链表(比如:driver链表)里面,

而硬件相关这边:device_add会将device这个结构体放到链表上去

现在我们好奇的是,device这边硬件相关的怎么和driver这边比较稳定的代码相联系起来呢?


我们知道,device_add会将device这个结构体放到链表上面之后,还会从driver中把它取出来进行比对,用的函数是总线里面的比较函数match:将driver与device进行比较能不支持device,能支持的话就调用driver里面的 .probe函数

现在我们来看看device_add做什么事情:

如图1所示,把device放入bus的dev的链表

2,从总线的DRV链表取出每一个DRV,用总线的match函数判断drv能否支持device,如果能够支持的话,调用.PROBE函数

现在我们来看看drever_register做什么事情:

如图1所示,将driver放入链表

2,从device取出,与其一一比较,用bus的match函数

3,如果能够支持,调用probe函数

注意了,这只不过是注册并且左右建立连接的一种机制,driver和device只不过是一种结构体,里面怎么实现由我们自己决定,这里只不过是提供一个机制,将一个驱动程序强制分为左右两边。

现在我们来看一个驱动程序,文件路径为:drivers\input\keyboard\ gpio_keys.c

现在我们来查看一下platform_driver_register(&gpio_keys_device_driver)里面有什么东西

&platform_bus_type为一个虚拟总线,里面有一个函数match,

那么如何让左右两边同时支持呢我们查看一下match函数:

从代码可以看出,匹配是通过名字来判断是否支持,从而调用.PROBE函数

如果想让probe函数能被调用,则左边应该有一个同名的platform device

************************************************** ***********************

敲重点了!!!!!!!!!!

************************************************** ***********************

现在我们干脆来写一个驱动程序实现点灯功能,来更好了解一下分层分离的概念

比如说,开发板有3个led灯,而我们只想点一盏灯,该如何做?

我们来写一个驱动程序,将其强制分为左右两边

1,新建两个文件:led_dev.cled_drv.c

led_dev.c 文件中,分配/设置/注册一个platform_device

分配:

设置

注册入口函数和出口函数

修饰一下入口函数和出口函数,并加上GPL协议:

添加头文件:

添加release函数:

现在硬件相关的代码已经写好了,现在我们来写另一边,即driver

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

led_drv.c 文件中,分配/设置/注册一个的platform_driver

添加头文件:


写出入口函数和出口函数并修饰一下,同时增加GPL协议:

定义一个platform driver,同时命名要相同

创建类名和相关变量等:

构造一个file_operation结构体:

现在我们来写一下这个函数:led_probe函数,根据platform_device的资源进行ioremap

 ioremap的作用英文的英文将一个IO  地址空间映射到内核的虚拟地址空间上去,便于访问,同时要注册字符设备驱动程序

而对于led_remove函数,要我们卸载字符设备驱动程序,同时写出iounmap

写出open函数:

写出write函数:

写出测试程序:

 

================================================== ==

我们现在来编译-一下:

如图1所示,将文件拷贝到服务器上去编译

2,将其他文件的生成文件拷贝到本文件夹中,并修改一下生成文件编译的文件名

3,输入使编译:


4,编译测试程序:arm-linux-gcc -o led_test led_test.c,并将编译后的两个 . ko 文件拷贝到根文件系统上去:

5,挂载NFS,并装载led_dev,ko文件,再装载led_drv.ko,并查看是否有dev/ LED:


使用测试程序。 . / led_test on 和 . /led_test off 即可查看led的亮灭情况

从这里我们就可以看到,本来一个很简单的东西,我们认为的将他拆分成两部分,左边为硬件相关的东西,右边为比较稳定的代码。

以上就是所谓的分离概念,分离经常用到的是所谓的设备驱动程序总线模型,这种模型只提供一种机制而已,在这种机制中,想实现什么是由我们自己决定的。



猜你喜欢

转载自blog.csdn.net/kxzkxzz/article/details/80637091