Linux驱动学习笔记 -- 驱动总线实验

驱动总线

在Linux系统中,除了硬件总线,还有一种软件虚拟出来的总线 – 驱动总线bus
这种驱动总线的作用:软件与硬件代码分离,提高程序的复用性

驱动总线分三个部分: 三者都是在/include/linux/device.h中定义

  • device - 关联硬件代码
struct device
  • device_driver - 关联软件代码
struct device_driver
  • bus_type - 管理总线,设置匹配规则,devicedevice_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

查看打印的调试信息内核消息:

[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

猜你喜欢

转载自blog.csdn.net/qq_36413982/article/details/112795926