1、引言
待补充,总线是linux设备驱动的一种软件架构思想。
2、总线概述
总线设备驱动一共分为3步,第一是学习总线,第二是学习设备,第三步是学习驱动。
这张图不全,不管是总线还是设备还是驱动,都分为结构描述、注册、注销这三部分。
2.1第一步:总线创建-结构体-注册-注销
如何创建一条总线?
bus.c #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> MODULE_LICENSE("GPL"); int my_match(struct device *dev, struct device_driver *drv) { //两个结构体,一个代表设备,一个代表驱动 return 0; } struct bus_type my_bus_type={ .name = "my_bus", .match = my_match, }; EXPORT_SYMBOL(my_bus_type); int my_bus_init(void) { int ret=0; ret = bus_register(&my_bus_type); } void my_bus_exit(void) { bus_unregister(&my_bus_type); } module_init(my_bus_init); module_exit(my_bus_exit);
:加载之后,会在sys/bus总线目录下多出来我们定义的总线
2.2 如何创建驱动?并且挂载在上面的总线上
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)//谁来触发probe函数呢??? { printk("driver found the device it can handler\n"); return 0; } struct device_driver my_driver = { .name = "my_dev", .bus = &my_bus_type,//这里引用了上面创建的总线结构体 .probe = my_probe, }; int my_driver_init(void) { int ret; ret = driver_register(&my_driver); } void my_driver_exit(void) { driver_unregister(&my_driver); } module_init(my_driver_init); module_exit(my_driver_exit); Makefile obj-m := bus.o driver.o KDIR := /home/aston/040-linux-tq2440/linux-tq2440 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
在讲讲总线设备驱动的注册过程:
2.3 第三步:如何创建并且在总线上挂载一个设备??
前面两步我们已经加载好了总线和驱动
device.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; struct device my_device={ .init_name = "my_device", .bus = &my_bus_type, }; int my_device_init(void) { int ret; ret = device_register(&my_device); } void my_device_exit(void) { device_unregister(&my_device); } module_init(my_device_init); module_exit(my_device_exit);
问题1、设备上线后,谁来触发driver的probe函数??谁来粗发bus的match函数??
这个应该在内核里面有答案,match匹配到之后,才会调用到对应的驱动。也就说上层有地方会持续的扫描调用match函数,或者由中断触发。当发现有device上线后,match会拿着device的name去逐一和当前的driver的name进行匹配。找到之后就会调用probe函数。这也是到现在为止,把这几个ko加载后没反应的原因。
需要修改bus.c bus.c #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/device.h> MODULE_LICENSE("GPL"); int my_match(struct device *dev, struct device_driver *drv) { //两个结构体,一个代表设备,一个代表驱动 //return !strncmp(dev->init_name,drv->name,strlen(drv->name)); //上电后发现init_name是空指针,导致出现堆栈回溯异常 return !strncmp(dev->kobj.name, drv->name, strlen(drv->name)); } /*在添加设备时 int device_add(struct device *dev) 问题:这个函数在什么时候被调用呢???? { if (dev->init_name) { dev_set_name(dev, "%s", dev->init_name); dev->init_name = NULL;所以我们需要比较的是dev->kobj.name } } */ struct bus_type my_bus_type={ .name = "my_bus", .match = my_match; }; EXPORT_SYMBOL(my_bus_type); int my_bus_init() { int ret=0; ret = bus_register(&my_bus_type); } void my_bus_exit() { bus_unregister(&my_bus_type); } module_init(my_bus_init); module_init(my_bus_exit); Makefile obj-m := bus.o driver.o device.o KDIR := /home/aston/040-linux-tq2440/linux-tq2440 all: make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm clean: rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
问题1:device_add函数由谁来调用??