驱动总线
在Linux系统中,除了硬件总线,还有一种软件虚拟出来的总线 – 驱动总线bus
这种驱动总线的作用:软件与硬件代码分离,提高程序的复用性
驱动总线分三个部分: 三者都是在/include/linux/device.h
中定义
- device - 关联硬件代码
struct device
- device_driver - 关联软件代码
struct device_driver
- bus_type - 管理总线,设置匹配规则,device和device_driver通过匹配规则进行匹配,匹配成功
struct device_driver
中的probe()函数
就会被执行
struct bus_type
总线初始化
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
if (!bus_kset)
return -ENOMEM;
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
if (!system_kset)
return -ENOMEM;
return 0;
}
内核启动该函数会被执行进而初始化驱动总线
总线初始化后会在会创建总线对应的/sys/bus/
目录
总线注册/卸载
1、注册新的总线:
int bus_register(struct bus_type *bus);
2、卸载总线:
void bus_unregister(struct bus_type *bus)
设备注册/卸载
1、设备注册:添加设备,关联硬件相关代码
int device_register(struct device *dev)
2、设备卸载:
void device_unregister(struct device *dev)
驱动注册/卸载
**1、驱动注册:**添加驱动,关联软件相关代码
int driver_register(struct device_driver *drv)
2、驱动卸载:
void driver_unregister(struct device_driver *drv)
注册新总线实验
1、总线注册
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
//设置的device和driver的匹配规则 : 设置通过名字匹配
int xbus_match(struct device *dev, struct device_driver *drv)
{
if (strcmp(dev_name(dev), drv->name) == 0) /* 匹配成功 */
{
printk("xbus device & driver match success\r\n");
return 1;
}
return 0;
}
static struct bus_type xbus = {
.name = "xbus", //注册名为xbus的总线
.match = xbus_match,
};
EXPORT_SYMBOL(xbus); //导出xbus全局符号
static int __init xbus_init(void)
{
int ret = bus_register(&xbus); //注册xbus总线
printk("register xbus\r\n");
return ret;
}
static void __exit xbus_exit(void)
{
bus_unregister(&xbus); //卸载xbus总线
printk("unregsiter xbus\r\n");
}
module_init(xbus_init);
module_exit(xbus_exit);
MODULE_LICENSE("GPL");
2、注册设备
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
extern struct bus_type xbus; // 注册的xbus总线
//device被卸载时被执行
static void xbus_device_release(struct device *dev)
{
printk("xbus device relase\r\n");
printk("%s %s\r\n", __FILE__, __func__);
}
static struct device xbus_dev = {
.init_name = "xbusdev",
.bus = &xbus, //device关联注册的xbus总线
.release = xbus_device_release,
};
static int __init xbus_device_init(void)
{
int ret = device_register(&xbus_dev); //注册device
return ret;
}
static void __exit xbus_device_exit(void)
{
device_unregister(&xbus_dev); //卸载device
printk("xbus_device exit\r\n");
}
module_init(xbus_device_init);
module_exit(xbus_device_exit);
MODULE_LICENSE("GPL");
3、注册驱动
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
extern struct bus_type xbus; // 注册的xbus总线
//device和driver匹配成功该函数就会被执行
static int xdrv_probe(struct device *dev)
{
printk(KERN_INFO"%s-%s\n", __FILE__, __func__);
return 0;
}
//驱动被卸载时执行
static int xdrv_remove(struct device *dev)
{
printk(KERN_INFO"%s-%s\n", __FILE__, __func__);
return 0;
}
static struct device_driver xbus_drv = {
.name = "xbusdev",
.bus = &xbus,
.probe = xdrv_probe,
.remove = xdrv_remove,
};
static int __init xbus_drv_init(void)
{
printk(KERN_INFO"xbus driver init\n");
driver_register(&xbus_drv);
return 0;
}
static void __exit xbus_drv_exit(void)
{
printk(KERN_INFO"xbus driver exit\n");
driver_unregister(&xbus_drv);
}
module_init(xbus_drv_init);
module_exit(xbus_drv_exit);
MODULE_AUTHOR("Ares");
MODULE_LICENSE("GPL");
注册的总线xbus是通过名字匹配,device的名字设置为.init_name = "xbusdev"
,所以driver的名字(.name = "xbusdev")
设置成和device一样
4、编译模块
KERNEL_DIR=/home/ares/ebf-buster-linux/
ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH CROSS_COMPILE
obj-m += xbus.o xbus_device.o xbus_driver.o
all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
.PHONE:clean
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
5、加载模块
1、总线模块 sudo insmod xbus.ko
2、device sudo insmod xbus_device.ko
3、driver sudo insmod xbus_driver.ko
查看打印的调试信息内核消息:
扫描二维码关注公众号,回复:
12911579 查看本文章
[39477.494030] xbus driver init
[39477.494092] xbus device & driver match success //device 和 driver匹配成功
[39477.494172] /home/ares/drivers_learning/xbus/xbus_driver.c-xdrv_probe //device和driver匹配成功执行xdrv_probe函数
查看/sys/bus/目录:
ls /sys/bus/
有了一个和注册的xbus总线对应的文件夹:
查看/sys/bus/xbus/目录下的内容:
devices目录 - 表示里面是挂载该总线的设备
drivers目录 - 表示里面是挂载在该总线的驱动
查看/sys/bus/xbus/devices和drivers目录下的内容:
两个目录的内容是一致,就是自己注册的xbusdev
6、卸载模块
1、sudo rmmod xbus_device.ko
2、sudo rmmod xbus_driver.ko
3、sudo rmmod xbus.ko //由于xbus_device.ko和xbus_driver.ko依赖于xbus.ko,所以不能先卸载xbus.ko
查看打印的调试信息:
[40574.523079] /home/ares/drivers_learning/xbus/xbus_device.c xbus_device_release
[40574.523090] xbus_device exit
[40586.124660] xbus driver exit
[40592.489635] unregsiter xbus