驱动学习回顾——Linux下bus设备模型
2017-08-21 13:14
567 查看
关于Linux的驱动学习有三个点是应该掌握的,即:总线,驱动,设备。不管是一些物理总线(如:I2C,SPI等)的抽象,还是为了增加设备“容量”而定义的虚拟总线(plat-from),都是围绕着这三个进行。即:一个符合Linux设备驱动模型的device和device_dvrier都挂在一个bus上,由bus来进行两者匹配,进行双向绑定。
下面简单地给出自己简单的学习过程。
下面给出一段创建总线的简单代码:
解读:
1、从
2、
3、
(关于kobject:http://blog.chinaunix.net/uid-20672257-id-3147337.html 比较复杂……)
4、
简单驱动代码:
这里同样有
简单设备代码:
同样有
使用Makefile编译这三个模块:
将
会在串口打印出
简单分析了bus、driver、device之间的联系,实际上在Linux中内核的处理是很复杂的,在这只是将其一小部分拿出来分析编写了一下,目的是为了理解这三者的关系。
参考资料:
http://www.wowotech.net/linux_kenrel/bus.html
http://bbs.csdn.net/topics/390599875
http://blog.csdn.net/skdkjzz/article/details/38927907
下面简单地给出自己简单的学习过程。
一、总线
总线这个概念在内核中在include/linux/device.h路径下是由bus_type结构体表示。详情可自行阅读源代码。
name是总线的名字,
match函数指针是device_driver和device的匹配规则,具体地说,当一个device被加入时,会和bus上的所有device_driver进行匹配操作,如果有device_driver能支持这个device,则匹配成功,match返回非0值。
下面给出一段创建总线的简单代码:
/********************************************************************************* * Copyright: (C) 2017 TangBin<tangbinmvp@gmail.com> * All rights reserved. * * Filename: bus.c * Description: This file * * Version: 1.0.0(08/20/2017) * Author: TangBin <tangbinmvp@gmail.com> * ChangeLog: 1, Release initial version on "08/20/2017 07:53:13 PM" * ********************************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> int match_t(struct device *dev, struct device_driver *drv) { return !strncmp(dev->kobj.name,drv->name,strlen(drv->name)); } struct bus_type bus_type_t = { .name = "bus_t", .match = match_t, }; EXPORT_SYMBOL(bus_type_t); int bus_t_init(void) { int result; result = bus_register(&bus_type_t); return result; } void bus_t_exit(void) { bus_unregister(&bus_type_t); } module_init(bus_t_init); module_exit(bus_t_exit); MODULE_AUTHOR("Tangbin"); MODULE_LICENSE("GPL");
解读:
1、从
module_init开始看,进入到
bus_t_init中,由
bus_register(&bus_type_t)函数注册总线。(
bus_register函数在
drivers/base/bus.c路径下)
2、
bus_type_t是在
bus_type结构体定义,里面定义了成员
name和
match。 name即为这个bus的名字。
3、
match匹配了
match_t函数,当有新的驱动(或设备)加到这条总线时,总线就会调用
match指向的函数,一一匹配是否有对应的驱动(或设备)存在,匹配成功则返回非0值,比较的方式就是检测设备的名字
dev->kobj.name和驱动的名字
drv->name是否相等。在这里设备的名字是
dev->kobj.name是因为在
drivers/base/core.c的
device_add的函数中:
if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL; }
dev->init_name会被赋值为
NULL导致加载模块后引发空指针异常。
(关于kobject:http://blog.chinaunix.net/uid-20672257-id-3147337.html 比较复杂……)
4、
EXPORT_SYMBOL(bus_type_t),由于几个模块的依赖,使用了内核提供的机制,以
EXPORT_SYMBOL内定义的函数或者符号对全部内核代码公开,不用修改内核代码即可在其它模块中调用。
二、驱动
struct device_driver在内核中表示驱动
name为驱动名字,
bus指驱动所在的哪条总线,
probe指向的函数则是匹配完后进行一系列初始化的函数,相应地,
remove指向的函数是释放资源的作用。
简单驱动代码:
/********************************************************************************* * Copyright: (C) 2017 TangBin<tangbinmvp@gmail.com> * All rights reserved. * * Filename: driver.c * Description: This file * * Version: 1.0.0(08/20/2017) * Author: TangBin <tangbinmvp@gmail.com> * ChangeLog: 1, Release initial version on "08/20/2017 07:55:39 PM" * ********************************************************************************/ #include <linux/device.h> #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> extern struct bus_type bus_type_t; int probe_t(struct device *dev) { printk("hello,world\n"); return 0; } struct device_driver driver_t = { .name = "device", .bus = &bus_type_t, .probe = probe_t, }; int driver_t_init(void) { int result; result = driver_register(&driver_t); return result; } void driver_t_exit(void) { driver_unregister(&driver_t); } module_init(driver_t_init); module_exit(driver_t_exit); MODULE_AUTHOR("Tangbin"); MODULE_LICENSE("GPL");
这里同样有
driver_register和
driver_unregister进行注册和注销。
三、设备
struct device在内核中表示设备
init_name设备名,
bus为所在总线。
简单设备代码:
/********************************************************************************* * Copyright: (C) 2017 TangBin<tangbinmvp@gmail.com> * All rights reserved. * * Filename: device.c * Description: This file * * Version: 1.0.0(08/20/2017) * Author: TangBin <tangbinmvp@gmail.com> * ChangeLog: 1, Release initial version on "08/20/2017 08:06:25 PM" * ********************************************************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> extern struct bus_type bus_type_t; struct device device_t = { .init_name = "device", .bus = &bus_type_t, }; int device_t_init(void) { int result; result = device_register(&device_t); return result; } void device_t_exit(void) { device_unregister(&device_t); } module_init(device_t_init); module_exit(device_t_exit); MODULE_AUTHOR("Tangbin"); MODULE_LICENSE("GPL");
同样有
device_register和
device_unregister进行注册和注销。
使用Makefile编译这三个模块:
LINUX_SRC ?= ../my-linux-3.0 CROSS_COMPILE=/opt/buildroot-2012.08/arm920t/usr/bin/arm-linux- obj-m := bus.o device.o driver.o modules: @make -C $(LINUX_SRC) M=`pwd` modules @make clean clean: rm -f *.ko.* *.o *mod.c *.order *.symvers
将
bus.ko、
driver,ko、
device.ko下到开发板,依次
insmod
会在串口打印出
hello,world。 哈哈,又是另一种“hello,world”的方法。
简单分析了bus、driver、device之间的联系,实际上在Linux中内核的处理是很复杂的,在这只是将其一小部分拿出来分析编写了一下,目的是为了理解这三者的关系。
参考资料:
http://www.wowotech.net/linux_kenrel/bus.html
http://bbs.csdn.net/topics/390599875
http://blog.csdn.net/skdkjzz/article/details/38927907
相关文章推荐
- Linux驱动模型学习(一)---字符设备驱动模型之一---使用字符设备驱动
- Linux设备驱动程式学习(13)-Linux设备模型(总线、设备、驱动程式和类)
- Linux设备驱动模型学习之基础篇--Kobject.txt翻译
- linux驱动学习---设备模型别人的理解(1)
- linux内核组件分析之--设备驱动模型之bus
- Linux内核部件分析--设备驱动模型之bus
- Linux设备驱动模型学习之基础篇--Kobject.txt翻译
- LINUX设备驱动之设备模型五--device&driver&bus(三)
- Linux内核之BUS驱动设备模型理解
- Linux设备模型中三个很重要的概念: 总线,设备,驱动.即bus,device,driver
- 嵌入式学习-驱动开发-lesson3-混杂设备驱动模型与linux中断处理流程
- LINUX设备驱动之设备模型四--device&driver&bus(二)
- LINUX设备驱动之设备模型三--device&driver&bus(一)
- Linux设备驱动模型探究--2(bus)
- 嵌入式 linux下kernel代码中设备驱动模型之bus
- LINUX设备驱动之设备模型五--device&driver&bus(三)
- LINUX设备驱动之设备模型四--device&driver&bus(二)
- LINUX 驱动学习之路 -设备模型之别人的理解(3)
- linux内核组件分析之--设备驱动模型之bus
- ldd3学习之十一(2):Linux设备模型---总线、设备、驱动