xbus.c
#include
#include
#include
int xbus_match(struct device *dev,struct device_driver *drv)
{
printk("%s-%s\n",__FILE__,__func__);
if(!(strncmp(dev_name(dev),drv->name,strlen(drv->name))))
{
printk("dev & drv match\n");
return 1;
}
return 0;
}
static struct bus_type xbus={
.name="xbus",
.match = xbus_match,
};
EXPORT_SYMBOL(xbus);
static char* bus_name = "xbus";
ssize_t xbus_test_show(struct bus_type *bus,char *buf)
{
return sprintf(buf,"%s\n",bus_name);
}
BUS_ATTR(xbus_test,S_IRUSR,xbus_test_show,NULL);
static __init int xbus_init(void)
{
printk("xbus init sucess!\n");
bus_register(&xbus);
bus_create_file(&xbus,&bus_attr_xbus_test);
return 0;
}
static __exit void xbus_exit(void)
{
printk("xbus exit sucess!\n");
bus_remove_file(&xbus,&bus_attr_xbus_test);
bus_unregister(&xbus);
}
module_init(xbus_init);
module_exit(xbus_exit);
MODULE_LICENSE("GPL");
加载内核模块,成功。
sudo insmod /mnt/xbus.ko
此时会在/sys/bus/下面创建一个xbus的目录项。
xbus里的devices和drivers目录项现在是空的,xbus_test文件别创建的属性文件,当使用cat命令时,就会在内部执行回调函数。
sudo cat xbus_test
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MfMcvPDJ-1669966720949)(linux的设备模型.assets/image-20221202100506048-16699665808181.png)]
可以看下属性文件的信息,就是我们之前设置的。
xdev.c
#include
#include
#include
extern struct bus_type xbus;
void xdev_release(struct device *dev)
{
printk("%s-%s\n",__FILE__,__func__);
}
struct device xdev={
.init_name="xdev",
.bus = &xbus,
.release = xdev_release,
};
unsigned long id = 0;
ssize_t xdev_id_show(struct device *dev,struct device_attribute *attr,char *buf)
{
return sprintf(buf,"%d\n",id);
}
ssize_t xdev_id_store(struct device *dev,struct device_attribute *attr,const char *buf,size_t count)
{
//将buf里的字符串转为10进制,存在id中
kstrtoul(buf,10,&id);
return count;
}
//定义名为xdev_id的文件,当使用cat命令时,调用,echo命令时调用
DEVICE_ATTR(xdev_id,S_IRUSR|S_IWUSR,xdev_id_show,xdev_id_store);
static __init int xdev_init(void)
{
printk("xdev init sucess!\n");
device_register(&xdev);
device_create_file(&xdev,&dev_attr_xdev_id);
return 0;
}
static void __exit xdev_exit(void)
{
printk("xdev exit sucess!\n");
device_remove_file(&xdev,&dev_attr_xdev_id);
device_unregister(&xdev);
}
module_init(xdev_init);
module_exit(xdev_exit);
MODULE_LICENSE("GPL");
sudo insmod /mnt/xdev.ko
加载设备模块成功后,会在/sys/bus/xbus/device/目录下创建一个链接文件
指向的是/sys/device/xdev目录项
进入/sys/devices/xdev目录,xdev_id就是创建的属性文件
通过echo以及cat命令,可以进行修改和查询,如下所示:
drv.c
#include
#include
#include
extern struct bus_type xbus;
//当驱动和设备匹配成功,执行此函数
int xdrv_probe(struct device *xdev)
{
printk("%s-%s\n",__FILE__,__func__);
return 0;
}
//当注销驱动时,会执行此函数
int xdrv_remove(struct device *xdev)
{
printk("%s-%s\n",__FILE__,__func__);
return 0;
}
struct device_driver xdrv={
//要匹配的设备名字
.name="xdev",
//要挂载的总线
.bus = &xbus,
.probe = xdrv_probe,
.remove = xdrv_remove
};
char *name = "xdrv";
ssize_t drvname_show(struct device_driver *drv,char *buf)
{
return sprintf(buf,"%s\n",name);
}
//定义名为drvname的文件要和上面的drvname_show函数之前的一致
DRIVER_ATTR_RO(drvname);
static __init int xdrv_init(void)
{
printk("xdrv init sucess!\n");
driver_register(&xdrv);
driver_create_file(&xdrv,&driver_attr_drvname);
return 0;
}
static void __exit xdrv_exit(void)
{
printk("xdrv exit sucess!\n");
driver_remove_file(&xdrv,&driver_attr_drvname);
driver_unregister(&xdrv);
}
module_init(xdrv_init);
module_exit(xdrv_exit);
MODULE_LICENSE("GPL");
sudo insmod /mnt/xdrv.ko
加载设备模块成功后,会在/sys/bus/xbus/driver/目录下创建一个xdrv目录
进入/sys/bus/xbus/drivers/xdev目录,drvname就是创建的属性文件。
通过使用cat命令会打打印出之前设置的信息。
KERNEL_DIR=../ebf_linux_kernel/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
clean:
$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean
当将xbus.ko模块首先加载,xdev.ko和xdrv.ko加载顺序不要求。查看当前模块如下图:
卸载模块,先卸载xdev.ko或xdrv.ko,xbus.ko的卸载要在设备和驱动模块卸载后再卸载。