由于没有经过完整测试代码中可能会有不足之出,如有网友发现还请斧正
这是一个学习文档,所有代码仅供学习使用,请勿在生产环境中使用
代码在ubuntu 12.04,ubuntu 16.04,ubuntu 18.04下经过测试
[邮箱] :(liulf_pc@126.com)
[CSDN] :https://blog.csdn.net/qqstring
[仓库地址] :https://gitee.com/stringliulf/char_driver.git
[简书]:https://www.jianshu.com/u/752603033847
linux 总线(bus)驱动可以很好了理解linux的驱动模型
我有以下理解:
- 在bus驱动模型中分成bus,device,driver三个部分
- driver是真正的驱动,负责做事,在硬件驱动中负责操作硬件
- device是资源的提供者,负责给driver提供必要的资源
- bus是纽带,负责将driver与device联系起来
测试方法:
insmod bus.ko
insmod device.ko
insmod driver.ko
匹配过程描述:
- 首先将bus注册到内核,告诉内核有一个testbus总线
- 将device 注册到内核(实际上注册到了testbus总线的设备列表),即将一个device设备挂在testbus下
- 将driver 注册到内核,(实际上注册到了testbus总线的driver列表),即将一个driver驱动挂在testbus下
- 在注册device过程中会触发bus的match函数,如果总线上有与该device的匹配的驱动,则会调用该驱动的probe函数
- 同样在注册driver过程中也会触发match函数,如果总线有与该driver匹配的设备,则会调用该驱动的probe函数
bus代码
bus只需要完成match的工作就可以
代码中使用设备名进行匹配,实际的驱动中会比这个要复杂点,比如usb可以使用 id进行匹配,match函数返回1表示匹配成功,返回0表示失败
struct bus_type testbus = {
.name = "testbus",
.match = testbus_match,
};
EXPORT_SYMBOL(testbus);
int testbus_match(struct device *dev, struct device_driver *drv)
{
if(strncmp(drv->name, dev->kobj.name, strlen(drv->name)) == 0) {
printk(KERN_INFO "match success %s\n",drv->name);
return 1;
}else {
printk(KERN_INFO "not match %s\n",drv->name);
return 0;
}
}
static int testbus_init(void)
{
int ret;
ret = bus_register(&testbus);
return ret;
}
static void testbus_exit(void)
{
bus_unregister(&testbus);
printk(KERN_ALERT "unregiste %s %s\n",__func__,testbus.name);
}
module_init(testbus_init);
module_exit(testbus_exit);
MODULE_LICENSE("GPL");
driver代码
extern struct bus_type testbus;
struct device_driver* mydrv = NULL ;
int mydrv_probe(struct device *dev)
{
printk(KERN_INFO "%s\n",__func__);
return 0;
}
int mydrv_remove(struct device *dev)
{
printk(KERN_INFO "%s\n",__func__);
return 0;
}
static int mydrv_init(void)
{
int ret = 0;
mydrv = kzalloc(sizeof(*mydrv), GFP_KERNEL);
mydrv->name = "testdevice";
mydrv->bus = &testbus;
mydrv->probe = mydrv_probe;
mydrv->remove = mydrv_remove;
ret = driver_register(mydrv);
return ret;
}
static void mydrv_exit(void)
{
printk(KERN_ALERT "%s\n",__func__);
driver_unregister(mydrv);
kfree(mydrv);
}
module_init(mydrv_init);
module_exit(mydrv_exit);
MODULE_LICENSE("GPL");
device代码
extern struct bus_type testbus;
struct device* mydev;
static void mydev_release(struct device *dev)
{
printk(KERN_INFO "%s\n",__func__);
}
static int mydev_init(void)
{
int ret = 0;
mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
mydev->init_name = "testdevice";
mydev->bus = &testbus;
mydev->release = mydev_release;
ret = device_register(mydev);
return ret;
}
static void mydev_exit(void)
{
printk(KERN_INFO "%s\n",__func__);
device_unregister(mydev);
kfree(mydev);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
[邮箱] :(liulf_pc@126.com)
[CSDN] :https://blog.csdn.net/qqstring
[仓库地址] :https://gitee.com/stringliulf/char_driver.git