iTOP-4412全能版采用四核Cortex-A9,主频为1.4GHz-1.6GHz,配备S5M8767 电源管理,集成USB HUB,选用高品质板对板连接器稳定可靠,大厂生产,做工精良。接口一应俱全,开发更简单,搭载全网通4G、支持WIFI、蓝牙、陀螺仪、CAN总线、RS485总线、500万摄像头等模块,稳定运行Android 4.0.3/Android 4.4操作,系统通用Linux-3.0.15+Qt操作系统(QT支持5.7版本),Ubuntu版本:12.04,接口智能分配 方便好用。
第四十二章 驱动注册
前面的实验介绍过注册驱动的流程,注册的时候需要和设备匹配,简单介绍了将驱动注册到平台设备的结构体“platform_driver_register”,并没有介绍怎么使用使用。本章就个大家详细介绍如何使用这个结构体来注册驱动。
本节配套视频:
“视频 07_驱动注册”
源码
“probe_linux_module”
42.1 platform_driver_register和platform_driver_unregister函数
platform_driver_register 函数和 platform_driver_unregister 函数用于注册和卸载驱动。
如下图所示,在 Linux 源码目录下,使用命令“vim include/linux/platform_device.h”。
如上图所示。
注册驱动的函数:
extern int platform_driver_register(struct platform_driver *)
卸载驱动的函数:
extern void platform_driver_unregister(struct platform_driver *)
具体这两个函数是怎么实现的,大家其实不用去关心,都是前人做好的,只要掌握如何调用即可。
这两个函数都会调用一个 platform_driver 类型的结构体。
42.2 platform_driver 结构体
前一小节介绍到注册和卸载驱动的函数需要调用 platform_driver 类型结构体。这个结构体非常重要,大家一定要掌握它的使用方法。
如下图所示,这个结构体也是定义在“include/linux/platform_device.h”头文件中。
这个结构体需要好好分析,这个结构体提非常非常的重要,几乎所有的驱动都会用到。
该结构中包含了一组操作函数和一个 struct device_driver 的对像。在驱动中首先要做的就是定义 platform_driver 中的函数,并创建这个结构的一个对象实例, 然后在 init()函数中调用 platform_driver_register()向系统注册驱动。
函数 int (*probe)(struct platform_device *);
主要是进行设备的探测和初始化。例如想调用一个 GPIO,那么首先需要探测这个 GPIO 是否被占用了,如果被占用了那么初始化失败,驱动注册也就失败了;如果没有被占用,那么就申明要占用它。
该函数中一般还会添加生成设备节点的函数,如果初始化成功,那么就会需要添加设备节点。设备节点的知识在下一节介绍。
函数 int (*remove)(struct platform_device *);
移除驱动,该函数中一般用于去掉设备节点或者释放软硬件资源。
接着的三个函数:
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
从字面上就很好理解了,关闭驱动,悬挂(休眠)驱动以及恢复的时候该驱动要做什么。接着的结构体 struct device_driver driver;
主要包含两个参数,一个是 name 参数,驱动名称(需要和设备驱动结构体中的 name 参数一样);一个是 owner,一般是 THIS_MODULE。
下面给接着给大家介绍一个小知识点,以 platform_driver 结构体中的参数 probe 为例,这个参数指向 platform_driver_probe 函数,如下图所示。
在视频中没有介绍这个参数 platform_driver 是从哪里传来的。
大家打开平台文件,看一下注册设备的代码,如下图所示,是 HELLO_CTL 的结构体。
上图红色的结构体和 platform_driver_probe 函数的第一个参数类型一样,如果你注册一个 HELLO_CTL 驱动,那么你的初始化函数 platform_driver_probe 就会调用这个结构体。
虽然这个结构体在这里很简单,但是在后面专门的移植课程中,你会发现移植中有部分工作是解决这个结构体中的问题,另一部分工作是调试 bug。在具体使用的时候再详细介绍相关知识,这里只要知道注册驱动的时候会调用平台文件中对应结构体即可。
42.3 实验操作
在前面“实验 2mini_linux_module”的基础上添加注册驱动的代码。
如下图所示,是“mini_linux_module.c”的代码。
先将这个文件名改为 probe_linux_module.c。
然后在 probe_linux_module.c 文件中开始修改和添加带代码。
如下图所示,首先需要添加头文件“#include <linux/platform_device.h>”,然后定义一个宏变量 DRIVER_NAME,定义为“hello_ctl”,需要和前面注册的 hello 设备的名称相同。
然后在模块入口和出口调用函数 platform_driver_register 和platform_driver_unregister,如下图所示,先将参数名定义为“&hello_driver”。另外注册驱动的时候,会返回数值,将其打印出来判断是否注册成功。
如下图所示,定义结构体“hello_driver”。
driver 中的 name 参数就是驱动名称,这里将前面定义的宏变量 DRIVER_NAME 赋给它;另外一个参数 owner 一般默认为 THIS_MODULE。
然后定义函数 hello_probe、hello_remove、hello_shutdown、hello_suspend、hello_resume。
如上图所示,这里在 hello_probe 函数中添加打印信息“printk(KERN_EMERG "\tinitialized\n");”
如果设备和驱动匹配成功就会进入函数 hello_probe 打印“initialized”。
接着需要修改一下 Makefile 文件,将”mini_linux_module.o ”改为“probe_linux_module.o”,注释部分用户可以自己修改,如下图所示。
在Ubuntu 中的目录“/home/topeet”中新建目录“probe_linux_module”,拷贝驱动文件“probe_linux_module.c”和编译文件“Makefile”到新建中,如下图所示。
进入“probe_linux_module”目录,使用命令“make”编译“probe_linux_module.c”,如下图所示,生成模块文件“probe_linux_module.ko”。
启动开发板,拷贝“probe_linux_module.ko”到 U 盘,将 U 盘插入开发板,加载驱动文件“probe_linux_module.ko”,如下图所示,可以看到打印出了“initialized”,表明进入了 probe 函数。
使用命令“rmmod probe_linux_module”卸载驱动,可以看到打印“HELLO WORLD exit!”,表明卸载成功。