总线设备驱动模型

总线:创建一条总线,跟我们前面的按键一样,首先是描述总线结构,接着是注册总线,注销总线。总线设备,例如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. 驱动进化之路:总线设备驱动模型

    文章目录 1 驱动编写的3种方法 1.1 传统写法 1.2 总线设备驱动模型 1.3 设备树 2 在 Linux 中实现"分离":Bus/Dev/Drv 模型 2.1 模型 2.2 ...

  2. Linux SPI总线设备驱动模型详解

    随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...

  3. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之总线设备驱动模型

    文章目录 前言 1.驱动编写的三种方法 1.1.传统写法 1.2.总线驱动模型 1.3.设备树驱动模型 2.Linux实现分离:Bus/Dev/Drv模型 2.1.Bus/Dev/Drv模型 2.2. ...

  4. 【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 ...

  5. linux驱动开发篇(三)—— 总线设备驱动模型

    linux系列目录: linux基础篇(一)--GCC和Makefile编译过程 linux基础篇(二)--静态和动态链接 ARM裸机篇(一)--i.MX6ULL介绍 ARM裸机篇(二)--i.MX6 ...

  6. Linux驱动——驱动分离思想和总线设备驱动模型

    驱动分离思想: 在传统的字符设备驱动思想中一个驱动程序对应一个硬件资源,在驱动入口函数中对资源进行配置,在file_operation中对各个硬件资源进行操作.这种思想使得内核中驱动代码变得庞大,为了 ...

  7. linux一个spi总线挂多个设备,Linux SPI总线设备驱动模型详解

    随着技术不断进步,系统的拓扑结构越来越复杂,对热插拔.跨平台移植性的要求越来越高,早期的内核难以满足这些要求,从linux2.6内核开始,引入了总线设备驱动模型.其实在linux2.4总线的概念就已经 ...

  8. [国嵌攻略][125][总线设备驱动模型]

    总线模型 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求越来越高,2.4内核已经难以满足这些需求.为了适应这种形势的需要,从Linux2.6内核开始提供了全新的设备驱动模 ...

  9. Linux总线驱动设计(1)-总线设备驱动模型

    1.总线模型概述 随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求.为适应这种形势的需要,从Linux 2.6内核开始提供了全新的 ...

  10. LED 模板驱动程序的改造:总线设备驱动模型

    文章目录 1 概述 2 代码实现 3 代码分析 3.1 注意事项 1 概述 原来的框架: 要实现的框架: 2 代码实现 代码结构如下: board_A_led.c: #include <linu ...

最新文章

  1. Python标准库:内置函数tuple([iterable])
  2. Node.js中模块加载机制
  3. 双指针解决数组排序问题
  4. python采用单例模式游戏_Python实现Singleton模式的方式详解
  5. WSCRIPT与CScript区别解释
  6. Objective-C利用协议实现回调函数(类似java的回调函数)
  7. scala读取mysql文件_9. Scala操作外部数据 文件读取,xml,Excel,MySQL
  8. composer安装
  9. android logo:内核、android开机动画
  10. node url模块
  11. 上班时真的很困怎么办
  12. 机器学习思维导图(基于sklearn)
  13. python程序写诗_python:为你写诗
  14. ios app图标尺寸设置
  15. 利用数据库进行肿瘤基因的挖掘
  16. UI基础一:简单的BOL查询
  17. 什么是构造方法,为什么要使用构造方法
  18. 前端:margin、padding、float一篇文章彻底理解
  19. 利用JavaScript生成动态添加歌单
  20. 校招c语言笔试题数组,华为校园招聘考试C语言C笔试题

热门文章

  1. ABB机械臂手眼标定
  2. 【linux内核分析与应用-陈莉君】字符设备驱动
  3. cesium 构建天空盒
  4. Node2Vec笔记
  5. c语言 程序段 数据段,C程序段(代码段、数据段、BSS段以及堆栈)的详解
  6. DB2 SQLCODE常见错误代码
  7. (五十一)时间序列分析二:平稳时间序列分析(ARMA)
  8. java坦克大战爆炸效果_Java坦克大战第一个坦克不爆炸问题
  9. [转]小D课堂 - 零基础入门SpringBoot2.X到实战_汇总
  10. 国内研究报告:区块链技术在票据P2…