linux_bus驱动

由于没有经过完整测试代码中可能会有不足之出,如有网友发现还请斧正
这是一个学习文档,所有代码仅供学习使用,请勿在生产环境中使用
代码在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

linux 总线(bus)驱动可以很好了理解linux的驱动模型
我有以下理解:
* 在bus驱动模型中分成bus,device,driver三个部分
* driver是真正的驱动,负责做事,在硬件驱动中负责操作硬件
* device是资源的提供者,负责给driver提供必要的资源
* bus是纽带,负责将driver与device联系起来

测试方法:

insmod bus.ko
insmod device.ko
insmod driver.ko

匹配过程描述:

  1. 首先将bus注册到内核,告诉内核有一个testbus总线
  2. 将device 注册到内核(实际上注册到了testbus总线的设备列表),即将一个device设备挂在testbus下
  3. 将driver 注册到内核,(实际上注册到了testbus总线的driver列表),即将一个driver驱动挂在testbus下
  4. 在注册device过程中会触发bus的match函数,如果总线上有与该device的匹配的驱动,则会调用该驱动的probe函数
  5. 同样在注册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

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值