8.总线设备驱动模型
总线设备驱动模型
总线:创建一条总线,跟我们前面的按键一样,首先是描述总线结构,接着是注册总线,注销总线。总线设备,例如usb总线,上面会有很多类型的usb的驱动,例如鼠标、键盘.....等,当我们把之一的usb插上的时候,usb总线会把每个驱动遍历一遍,找到相应的驱动程序执行。
接下来用bus.c创建一条总线。
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
int my_match(struct device *dv, struct device_driver *drv)
{
return 0;
}
struct bus_type my_bus_type=
{
.name="mybus",
.match=my_match,
};
int mybus_init()
{
int ret;
ret=bus_register(&my_bus_type);
return ret;
}
void mybus_exit()
{
bus_unregister(&my_bus_type);
}
module_init(mybus_init);
module_exit(mybus_exit);
Make通过,拷贝到开发板运行:出现这错误:
错误的提示是未定义的bus总线相关的未定义符号。主要的要用是,我们的驱动程序没有遵循GPL协议,加上MODULE_LICENSE("GPL");就可以了。
下面的mybus总线就是我们刚新建的:
接下来是总线驱动的实现:
上面的prode函数,当我们有设备加到总线的时候,当设备与总线的某个借口相匹配的时候,系统就会调用prode函数。对我的设备进行相应的初始化。
接下来在我们上面的总线挂接个驱动。
我们的driver.c的代码:
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
int my_probe(struct device *dev)
{
printk("<0> driver found the device it can handle!\n");
return 0;
//如果是实际应用的驱动,这里会做很多的硬件初始化操作。
}
struct device_driver my_driver=
{
.name="my_dev",
.bus = &my_bus_type,//驱动是属于那一条总线的。来自外部的。所以总线的代码
//要有EXPORT_SYMBOL符号导出标志
.probe=my_probe,
};
int mydriver_init()
{
int ret;
ret=driver_register(&my_driver);
return ret;
}
void mydriver_exit()
{
driver_unregister(&my_driver);
}
module_init(mydriver_init);
module_exit(mydriver_exit);
由于驱动程序用到bus.c里的my_bus_type。所以在该结构的下面导出这个符号:EXPORT_SYMBOL(my_bus_type);//符号输出。最后重新make一遍。把生成的bus.ko和driver.ko拷贝到开发板执行的结果如下:
[root@FORLINX6410]# insmod bus.ko
[root@FORLINX6410]# insmod driver.ko
[root@FORLINX6410]# cd /sys/bus/
[root@FORLINX6410]# ls
ac97 i2c mybus sdio usb
event_source mdio_bus platform serio usb-serial
hid mmc scsi spi
[root@FORLINX6410]# cd mybus/
[root@FORLINX6410]# ls
devices drivers_autoprobe uevent
drivers drivers_probe
[root@FORLINX6410]# cd drivers/
[root@FORLINX6410]# ls
my_dev
[root@FORLINX6410]#
上面的目录/sys/bus/存的是系统总线的各类接口,我们看到了我们创建的mybus总线,进去,打开驱动drivers的目录,里面有我们创建的驱动my_dev。这说明了我们在总线上成功地挂载了我们的驱动。
接下来在我们上面的总线挂接个设备。
Device.c的代码:
#include <linux/module.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
extern struct bus_type my_bus_type;
struct device my_dev=
{
.init_name = "my_dev",//与驱动一致
.bus = &my_bus_type,
};
int my_device_init()
{
int ret;
ret=device_register(&my_dev);
return ret;
}
void my_device_exit()
{
device_unregister(&my_dev);
}
module_init(my_device_init);
module_exit(my_device_exit);
对于我们的bus.c也需要做相应的修改。就是驱动程序和设备文件要对应上才能实现操作。把my_match函数修改如下:
int my_match(struct device *dev, struct device_driver *drv)
{
return !strncmp(dev->init_name,drv->name,strlen(drv->name));
//驱动程序和设备的匹配程序
}
最后就是在我们的Makefile里面添加device.o。后执行Make:
[root@FORFISH bus]# make
make -C /home/samba/linux-ok6410 M=/home/module/bus modules ARCH=arm CROSS_COMPILE=arm-linux-
make[1]: Entering directory `/home/samba/linux-ok6410'
CC [M] /home/module/bus/device.o
/home/module/bus/device.c:14: warning: function declaration isn't a prototype
/home/module/bus/device.c:21: warning: function declaration isn't a prototype
Building modules, stage 2.
MODPOST 3 modules
CC /home/module/bus/bus.mod.o
LD [M] /home/module/bus/bus.ko
CC /home/module/bus/device.mod.o
LD [M] /home/module/bus/device.ko
CC /home/module/bus/driver.mod.o
LD [M] /home/module/bus/driver.ko
make[1]: Leaving directory `/home/samba/linux-ok6410'
完成之后,拷贝bus.ko driver.ko.device.ko到开发板,测试。
[root@FORLINX6410]# insmod bus.ko
[root@FORLINX6410]# insmod driver.ko
[root@FORLINX6410]# insmod device.ko
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = cbcdc000
[0te=00000000
Internal error: Oop
Modules linked in: device(+) driver bus
CPU: 0 Tainted: G W (3.0.1 #439)
PC is at strncmp+0x14/0x68
LR is at my_match+0x2c/0x38 [bus]
pc : [<c01f9348>] lr : [<bf000064>] psr: 20000013
sp : cbd83e10 ip : cbd83e20 fp : cbd83e1c
r10: 00000000 r9 : bf008098 r8 : c07b121c
r7 : c0244e48 r6 : bf008090 r5 : bf008090 r4 : bf0040e4
r3 : 00000000 r2 : 00000006 r1 : bf0040e4 r0 : 00000000
Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 00c5387d Table: 5bcdc008 DAC: 00000015
Process insmod (pid: 128, stack limit = 0xcbd82268)
Stack: (0xcbd83e10 to 0xcbd84000)
3e00: cbd83e34 cbd83e20 bf000064 c01f9340
3e20: bf0040ec bf008090 cbd83e4c cbd83e38 c0244e78 bf000044 00000000 cbd83e50
3e40: cbd83e74 cbd83e50 c024405c c0244e54 cbc67b88 cc716874 bf008090 bf008090
3e60: bf0080c4 00000000 cbd83e94 cbd83e78 c0244f44 c0244000 00000000 bf008090
3e80: c0706008 00000000 cbd83ea4 cbd83e98 c0243e20 c0244ec8 cbd83efc cbd83ea8
3ea0: c0242994 c0243e00 00000000 00000000 00000001 00000000 cbd83f0c cbd83ec8
3ec0: cbd83ee4 cbd83ed0 c01f48f8 d1a3548d bf008090 bf008090 00000000 bf008138
3ee0: 00000000 cbd82000 bf00801c 00000000 cbd83f14 cbd83f00 c0242c4c c024257c
3f00: c07463c0 00000000 cbd83f24 cbd83f18 bf008030 c0242c3c cbd83f7c cbd83f28
3f20: c00343c8 bf008028 cbd83f64 cbd83f38 c0073e24 00000000 00000000 00000000
3f40: 00000000 000088a4 000d5bf9 bf008138 00000000 000088a4 000d5bf9 bf008138
3f60: 00000000 c0034ce8 cbd82000 00000000 cbd83fa4 cbd83f80 c0085960 c0034398
3f80: c00e8738 c00e8610 402704a8 000dfcf8 00000000 00000080 00000000 cbd83fa8
3fa0: c0034b40 c00858e0 402704a8 000dfcf8 01327038 000088a4 000d5bf9 ffff5f01
3fc0: 402704a8 000dfcf8 00000000 00000080 00000069 00000001 becf2e84 becf2e88
3fe0: becf2e88 becf2b34 00021cfc 40331d74 60000010 01327038 5fffe821 5fffec21
[<c01f9348>] (strncmp+0x14/0x68) from [<bf000064>] (my_match+0x2c/0x38 [bus])
[<bf000064>] (my_match+0x2c/0x38 [bus]) from [<c0244e78>] (__device_attach+0x30)
[<c0244e78>] (__device_attach+0x30/0x48) from [<c024405c>] (bus_for_each_drv+0x)
[<c024405c>] (bus_for_each_drv+0x68/0x94) from [<c0244f44>] (device_attach+0x88)
[<c0244f44>] (device_attach+0x88/0xa0) from [<c0243e20>] (bus_probe_device+0x2c)
[<c0243e20>] (bus_probe_device+0x2c/0x4c) from [<c0242994>] (device_add+0x424/0)
[<c0242994>] (device_add+0x424/0x6c0) from [<c0242c4c>] (device_register+0x1c/0)
[<c0242c4c>] (device_register+0x1c/0x20) from [<bf008030>] (init_module+0x14/0x)
[<bf008030>] (init_module+0x14/0x1c [device]) from [<c00343c8>] (do_one_initcal)
[<c00343c8>] (do_one_initcall+0x3c/0x188) from [<c0085960>] (sys_init_module+0x)
[<c0085960>] (sys_init_module+0x8c/0x1a4) from [<c0034b40>] (ret_fast_syscall+0)
Code: e92dd800 e24cb004 e3520000 0a00000e (e5d03000)
---[ end trace da227214a82491b9 ]---
Segmentation fault
[root@FORLINX6410]#
上面出现了空指针:是在strncmp里出现了空指针,这个空指针是init_name;但是我们在我的device.c里已经.init_name="my_dev",为什么还是空指针呢?接下来看内核代码:
首先是找device_register:
进入上面的device_add函数:会有下面的代码:
上面的代码就是把不为空的init_name,赋值给dev_set_name,然后自身的值变为NULL。所以,我们的程序出现空指针的原因。这个值被赋值到了成员kobj.name:
重新编译安装:
我们该了之后,看到了,我们的驱动使能了我们的设备,设备开始工作了。这样我们就实现了该功能。
流程:当我们往总线加设备的时候,我的总线会把设备和总线上的驱动,一一进行匹配,当匹配成功的时候,就会去调用驱动的my_probe这个函数。看到了打印的出现。
上面是先有驱动,再有设备,工作的。
那么现有设备,再有驱动呢。同样能实现:
转载于:https://www.cnblogs.com/FORFISH/p/5188565.html
8.总线设备驱动模型相关推荐
- 驱动进化之路:总线设备驱动模型
文章目录 1 驱动编写的3种方法 1.1 传统写法 1.2 总线设备驱动模型 1.3 设备树 2 在 Linux 中实现"分离":Bus/Dev/Drv 模型 2.1 模型 2.2 ...
- Linux SPI总线设备驱动模型详解
随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...
- 【嵌入式Linux】嵌入式Linux驱动开发基础知识之总线设备驱动模型
文章目录 前言 1.驱动编写的三种方法 1.1.传统写法 1.2.总线驱动模型 1.3.设备树驱动模型 2.Linux实现分离:Bus/Dev/Drv模型 2.1.Bus/Dev/Drv模型 2.2. ...
- 【Bus】编写一个Demo虚拟的总线-设备-驱动模型
文章目录 1. 前言 2. 总线驱动模型三要素 2.1 总线 2.2 设备 2.3 驱动 3. Demo Code 3.1 virt_bus_core.c 3.2 virt_device.c 3.3 ...
- linux驱动开发篇(三)—— 总线设备驱动模型
linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...
- Linux驱动——驱动分离思想和总线设备驱动模型
驱动分离思想: 在传统的字符设备驱动思想中一个驱动程序对应一个硬件资源,在驱动入口函数中对资源进行配置,在file_operation中对各个硬件资源进行操作.这种思想使得内核中驱动代码变得庞大,为了 ...
- linux一个spi总线挂多个设备,Linux SPI总线设备驱动模型详解
随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...
- [国嵌攻略][125][总线设备驱动模型]
总线模型 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求越来越高,2.4内核已经难以满足这些需求.为了适应这种形势的需要,从Linux2.6内核开始提供了全新的设备驱动模 ...
- Linux总线驱动设计(1)-总线设备驱动模型
1.总线模型概述 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求.为适应这种形势的需要,从Linux 2.6内核开始提供了全新的 ...
- LED 模板驱动程序的改造:总线设备驱动模型
文章目录 1 概述 2 代码实现 3 代码分析 3.1 注意事项 1 概述 原来的框架: 要实现的框架: 2 代码实现 代码结构如下: board_A_led.c: #include <linu ...
最新文章
- Python标准库:内置函数tuple([iterable])
- Node.js中模块加载机制
- 双指针解决数组排序问题
- python采用单例模式游戏_Python实现Singleton模式的方式详解
- WSCRIPT与CScript区别解释
- Objective-C利用协议实现回调函数(类似java的回调函数)
- scala读取mysql文件_9. Scala操作外部数据 文件读取,xml,Excel,MySQL
- composer安装
- android logo:内核、android开机动画
- node url模块
- 上班时真的很困怎么办
- 机器学习思维导图(基于sklearn)
- python程序写诗_python:为你写诗
- ios app图标尺寸设置
- 利用数据库进行肿瘤基因的挖掘
- UI基础一:简单的BOL查询
- 什么是构造方法,为什么要使用构造方法
- 前端:margin、padding、float一篇文章彻底理解
- 利用JavaScript生成动态添加歌单
- 校招c语言笔试题数组,华为校园招聘考试C语言C笔试题