xbus:打造自属的驱动总线
软件和硬件的代码分离,提高程序的复用性。
device:关联硬件代码
driver_devices:关联软件代码
bus_type:统一管理、设置match匹配规则(struct device和struct device_driver)
在struct bus_type里面设置1个链表头,将要管理的一系列struct device通过一个链表串联起来。
在struct bus_type里面设置另1个链表头,将要管理的一系列struct device_driver通过一个链表串联起来。
buses_init()函数
内核启动默认执行,创建名字为“bus”和“system”的kset对象。即/sys/下生成“bus”、“system”目录。
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;
}
bus_register()函数
总线注册。添加新的总线类型。
int bus_register(struct bus_type *bus)
函数做了哪些事情:
在/sys/bus下建立xbus目录项(xbus是自定义的名字,设置bus->name = “xbus”即可),并创建属性文件。
在/sys/bus/xbus下建立devices目录项,并创建属性文件。
在/sys/bus/xbus下建立drivers目录项,并创建属性文件。
(如上需要创建3个目录,因此bus_type结构体需要3个kobject)
初始化priv->klist_devices链表头
初始化priv->klist_drivers链表头
device_register()函数
设备注册。添加设备,关联硬件相关代码。
int device_register(struct device *dev)
在/sys/bus/xbus/devices下建立yyy目录项(那么struct device里面肯定要包含一个kobject)。
加入bus->priv->devices_kset链表。
加入bus->priv->klist_devices链表。
遍历bus->priv->klist_drivers,执行bus->match来寻找合适的drv。
dev关联driv,执行drv->probe()。
driver_register()函数
驱动注册。添加驱动,关联软件相关代码。
int driver_register(struct device_driver *drv)
在/sys/bus/xbus/drivers下建立zzz目录项(那么struct device_driver里面肯定要包含一个kobject)。
加入bus->priv->drivers_kset链表。
加入bus->priv->klist_drivers链表。
遍历bus->priv->klist_klist_devices链表,执行bus->match来寻找合适的dev。
dev关联driv,执行drv->probe()。
设备驱动模型框图
bus、dev、drv关系图
实验环节:xbus
xbus.c文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
int xbus_match(struct device *dev, struct device_driver *drv)
{
/* __FILE__和__func__ 这两个宏是在编译器里面定义的 */
printk(KERN_ALERT "%s-%s\n", __FILE__, __func__);
if(!strncmp(dev_name(dev), drv->name, strlen(drv->name))){
printk(KERN_ALERT "dev & drv match\n");
return 1;
}
return 0;
}
static struct bus_type xbus = {
.name = "xbus",
.match = xbus_match,
};
EXPORT_SYMBOL(xbus);
static int __init xbus_init(void)
{
int ret;
printk(KERN_ALERT "xbus init\n");
ret = bus_register(&xbus);
if(ret != 0) return -1;
return 0;
}
static void __exit xbus_exit(void){
printk(KERN_ALERT "xbus exit\n");
bus_unregister(&xbus);
}
module_init(xbus_init);
module_exit(xbus_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("couvrir");
MODULE_DESCRIPTION("led module");
MODULE_ALIAS("led module");
xdev.c文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
extern struct bus_type xbus;
void xdev_release(struct device *dev)
{
printk(KERN_ALERT "%s-%s\n", __FILE__, __func__);
}
static struct device xdev = {
.init_name = "xdev",
/* 指明dev属于哪一条总线 */
.bus = &xbus,
.release = xdev_release,
};
static int __init xdev_init(void)
{
int ret;
printk(KERN_ALERT "xdev init\n");
ret = device_register(&xdev);
if(ret != 0) return -1;
return 0;
}
static void __exit xdev_exit(void){
printk(KERN_ALERT "xdev exit\n");
device_unregister(&xdev);
}
module_init(xdev_init);
module_exit(xdev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("couvrir");
MODULE_DESCRIPTION("led module");
MODULE_ALIAS("led module");
xdrv.c文件
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
extern struct bus_type xbus;
int xdrv_probe(struct device *dev)
{
/* device和driver关联起来后会调用该函数 */
printk(KERN_ALERT "%s-%s\n", __FILE__, __func__);
return 0;
}
int xdrv_remove(struct device *dev)
{
printk(KERN_ALERT "%s-%s\n", __FILE__, __func__);
return 0;
}
static struct device_driver xdrv = {
.name = "xdrv",
/* 指明dev属于哪一条总线 */
.bus = &xbus,
.probe = xdrv_probe,
.remove = xdrv_remove,
};
static int __init xdrv_init(void)
{
int ret;
printk(KERN_ALERT "xdrv init\n");
ret = driver_register(&xdrv);
if(ret != 0) return -1;
return 0;
}
static void __exit xdrv_exit(void){
printk(KERN_ALERT "xdrv exit\n");
driver_unregister(&xdrv);
}
module_init(xdrv_init);
module_exit(xdrv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("couvrir");
MODULE_DESCRIPTION("led module");
MODULE_ALIAS("led module");
Makefile文件
KERNEL_DIR=/home/couvrir/桌面/ebf_linux_kernel_6ull_depth1/build_image/build
ARCH=arm
CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH CROSS_COMPILE
obj-m:=xbus.o xdev.o xdrv.o
all:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules
.PHONY:clean copy
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
sudo rm /home/couvrir/桌面/sharedir/*.ko
copy:
sudo cp *.ko /home/couvrir/桌面/sharedir
执行过程
虚拟机:执行make和make copy。生成.ko文件。
开发板(在挂载目录下执行):
sudo insmod xbus.ko
观察/sys/bus/下是否有xbus目录,xbus目录下会自动生成device和driver目录项。
sudo insmod xdev.ko
观察/sys/bus/xbus/device/下是否有xdev目录。
sudo insmod xdrv.ko
观察/sys/bus/xbus/driver/下是否有xdrv目录。
sudo rmmod xdrv
sudo rmmod xdev
sudo rmmod xbus
platform:虚拟的驱动总线
platform_device:继承device,关联硬件代码
platform_driver:继承device_driver,重设probe函数指针
platform(bus_type):统一管理、设置match匹配规则(struct platform_device和struct platform_driver)