在输入子系统那一章,一个驱动分为上下两层,现在我们要引入另外一个概念,叫做分层分离概念:
在输入子系统,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.c和led_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的亮灭情况
从这里我们就可以看到,本来一个很简单的东西,我们认为的将他拆分成两部分,左边为硬件相关的东西,右边为比较稳定的代码。
以上就是所谓的分离概念,分离经常用到的是所谓的设备驱动程序总线模型,这种模型只提供一种机制而已,在这种机制中,想实现什么是由我们自己决定的。