Linux总线驱动-01: 一个简单的示例
2011-04-14 17:02
429 查看
本文测试系统为:Ubuntu 10.10 x86_64 2.6.35-24-generic
总线是处理器与外设之间通信的通道。在当前版本的Linux设备模型(Linux Device Model, LDM)中,所有的设备都是通过总线相连的,甚至是通过虚拟的”platform”总线。总线之间可以互相插入,比如一个SCSI控制器(适配器)一般是一个PCI-E设备,而一个USB控制器一般是一个PCI设备。
在设备模型中,每类总线都有一个设备链表和驱动链表。每当有新的设备插入(必定会插入到某总线),驱动核心遍历新设备所在总线的驱动链表,给设备匹配驱动;每当有新的驱动插入(也必定插入到某总线),驱动核心遍历驱动所在总线的设备链表,对于没有关联上驱动的设备,会尝试匹配。驱动移除时,驱动核心通知相关驱动,驱动移除时,驱动核心通知所有该驱动关联的设备。这就是驱动核心实现的热插拔机制。LDD3的第十四章Linux设备模型对此有详细描述。
在新的驱动核心支持下,实现一个什么都不做的总线驱动是很简单的。如下,拷贝代码并保存为ycbus.c:
提供一个简单的Makefile文件完成编译。如下,拷贝内容并保存为Makefile,和ycbus.c置于同一目录):
注意,$(MAKE)和rm两行前面是TAB而不是空格。键入空格Makefile是不会工作的。
执行编译/加载命令:
在/sys/bus/ycbus下查看ycbus的信息:
如果tree命令不存在,安装tree即可:
在/proc/kallsyms下也可看到ycbus驱动的符号:
没有看到ycbus_driver_init,是因为在这个函数前加了__init,在驱动加载完毕后,内核会扔掉这部分代码以节省空间。尝试去掉ycbus_driver_init前面的__init,再次查看,会发现这个函数也在符号表中出现了:
符号表的第一列是符号所在内存地址,我使用的是64位机,如果在32位机上测试,则这些地址是32位的。第二列是符号属性,其中d表示符号数据段,t表示符号在文本段(text,又称代码段),想要知道符号属性等的详细信息,执行命令 man nm。第三列是符号名称。第四列是符号所在模块。
在目录/sys/module/ycbus下,以及文件 /proc/modules内部,都可以查找到ycbus的相关信息。执行lsmod | grep ycbus也可以得到一些信息:
其中第一列是模块名称,第二列是模块占用内存大小,第三列是引用计数。针对ycbus,其名称是ycbus,占用内存为1193字节,引用计数为0(没有人用它)。
事实上,对于上述的ycbus总线驱动,除了在上述文件/文件夹,或者命令可以看到部分相关信息以外,这个驱动什么都做不了。事实上,除了通过驱动核心注册代码,我们没有编写任何其他代码。
理解本节所描述的内容,对于实现一个实用的总线驱动是有帮助的。
总线是处理器与外设之间通信的通道。在当前版本的Linux设备模型(Linux Device Model, LDM)中,所有的设备都是通过总线相连的,甚至是通过虚拟的”platform”总线。总线之间可以互相插入,比如一个SCSI控制器(适配器)一般是一个PCI-E设备,而一个USB控制器一般是一个PCI设备。
在设备模型中,每类总线都有一个设备链表和驱动链表。每当有新的设备插入(必定会插入到某总线),驱动核心遍历新设备所在总线的驱动链表,给设备匹配驱动;每当有新的驱动插入(也必定插入到某总线),驱动核心遍历驱动所在总线的设备链表,对于没有关联上驱动的设备,会尝试匹配。驱动移除时,驱动核心通知相关驱动,驱动移除时,驱动核心通知所有该驱动关联的设备。这就是驱动核心实现的热插拔机制。LDD3的第十四章Linux设备模型对此有详细描述。
在新的驱动核心支持下,实现一个什么都不做的总线驱动是很简单的。如下,拷贝代码并保存为ycbus.c:
/* * ycbus: a software bus driver (virtual bus driver) * * a trivial ycbus driver */ #include <linux/device.h> #include <linux/module.h> struct bus_type ycbus_type = { .name = "ycbus", }; static int __init ycbus_driver_init(void) { printk(KERN_DEBUG "ycbus_driver_init/n"); return bus_register(&ycbus_type); } static void __exit ycbus_driver_exit(void) { printk(KERN_DEBUG "ycbus_driver_exit/n"); bus_unregister(&ycbus_type); } module_init(ycbus_driver_init); module_exit(ycbus_driver_exit); MODULE_AUTHOR("yc <cppgp@qq.com>"); MODULE_DESCRIPTION("yc pseudo-bus driver"); MODULE_LICENSE("GPL");
提供一个简单的Makefile文件完成编译。如下,拷贝内容并保存为Makefile,和ycbus.c置于同一目录):
# A trivial bus driver Makefile. Saved as “Makefile” exactly ifneq ($(KERNELRELEASE),) obj-m := ycbus.o else KERNDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C ${KERNDIR} M=${PWD} modules endif clean: rm -rf modules.order Module.symvers .tmp_versions ycbus.ko .ycbus.ko.cmd ycbus.mod.c ycbus.mod.o .ycbus.mod.o.cmd ycbus.o .ycbus.o.cmd
注意,$(MAKE)和rm两行前面是TAB而不是空格。键入空格Makefile是不会工作的。
执行编译/加载命令:
$ make $ sudo insmod ycbus.ko
在/sys/bus/ycbus下查看ycbus的信息:
$ tree /sys/bus/ycbus/ /sys/bus/ycbus/ ├── devices ├── drivers ├── drivers_autoprobe ├── drivers_probe └── uevent 2 directories, 3 files
如果tree命令不存在,安装tree即可:
$ sudo apt-get install tree
在/proc/kallsyms下也可看到ycbus驱动的符号:
$ cat /proc/kallsyms | grep ycbus ffffffffa0b82000 t ycbus_driver_exit [ycbus] ffffffffa0b82100 d __this_module [ycbus] ffffffffa0b82000 t cleanup_module [ycbus] ffffffffa0b82080 d ycbus_type [ycbus]
没有看到ycbus_driver_init,是因为在这个函数前加了__init,在驱动加载完毕后,内核会扔掉这部分代码以节省空间。尝试去掉ycbus_driver_init前面的__init,再次查看,会发现这个函数也在符号表中出现了:
$ cat /proc/kallsyms | grep ycbus ffffffffa0057028 t ycbus_driver_exit [ycbus] ffffffffa0057000 t ycbus_driver_init [ycbus] ffffffffa0057140 d __this_module [ycbus] ffffffffa0057028 t cleanup_module [ycbus] ffffffffa0057000 t init_module [ycbus] ffffffffa00570c0 d ycbus_type [ycbus]
符号表的第一列是符号所在内存地址,我使用的是64位机,如果在32位机上测试,则这些地址是32位的。第二列是符号属性,其中d表示符号数据段,t表示符号在文本段(text,又称代码段),想要知道符号属性等的详细信息,执行命令 man nm。第三列是符号名称。第四列是符号所在模块。
在目录/sys/module/ycbus下,以及文件 /proc/modules内部,都可以查找到ycbus的相关信息。执行lsmod | grep ycbus也可以得到一些信息:
$ lsmod | grep ycbus ycbus 1193 0
其中第一列是模块名称,第二列是模块占用内存大小,第三列是引用计数。针对ycbus,其名称是ycbus,占用内存为1193字节,引用计数为0(没有人用它)。
事实上,对于上述的ycbus总线驱动,除了在上述文件/文件夹,或者命令可以看到部分相关信息以外,这个驱动什么都做不了。事实上,除了通过驱动核心注册代码,我们没有编写任何其他代码。
理解本节所描述的内容,对于实现一个实用的总线驱动是有帮助的。
相关文章推荐
- 一个简单的Linux驱动示例
- 一个简单的Linux驱动
- IDDD 实现领域驱动设计-一个简单的 CQRS 示例
- linux 一个简单的字符设备驱动例子
- Linux字符设备驱动程序的一个简单示例
- linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(2)
- 一个最简单的Linux 2.6内核驱动模块
- linux简单字符驱动示例
- 编译和安装linux内核2.6.24,并且写一个简单的内核驱动测试之
- linux驱动—input输入子系统—The simplest example(一个最简单的实例)分析(1)
- 简单的linux字符型驱动示例
- Linux字符设备驱动程序的一个简单示例
- 一个简单的linux系统下的5*5的键盘驱动
- Linux下面一个简单的虚拟platform驱动
- Linux字符设备驱动程序的一个简单示例
- [ASP.NET 设计模式] 用Visual Studio2010搭建一个简单的分层结构示例Step by Step —— 01 准备工作
- 一个简单的Linux字符驱动
- Linux平台:一个简单的TCP6 server的示例代码(socket)
- Linux字符设备驱动程序的一个简单示例
- Linux字符设备驱动程序的一个简单示例(转)