设备模型六(bus, device, driver)

  • 前言
    前面讨论已经知道, kset, kobject相当于c++中的基类,会有上层容器去继承他们,c语言里面的继承也就是包含其数据结构的意思,而bus(总线), device(设备),驱动(驱动), 他们三个壮汉继承了他们,从而引出了设备模型的高级部分,这里我们要搞明白以下几点
    1.bus, device, driver的数据结构
    2.三者间的关系
    3.device与driver间的绑定
    开搞!

  • 1.bus, device, driver的数据结构

  • 1.1感性的认识什么是bus,device, driver
    bus,即总线, 根据<<设备模型一>>文章内容叙述,总线可以是真实总线的抽象,如i2c,也可以是非真实 的总线,为了一致统一, 非真实统一也要跟真实总线一样被抽象,即虚拟总线
    即 i2c(真实总线)---->抽象—>i2c_bus_type
    虚拟总线—>抽象—>platform
    所谓抽象,意思就是说把真实的总线(或虚拟总线)描述成一个数据结构
    对于加入系统中的硬件或者驱动(写代码时会把硬件或者驱动所依赖的总线提前写好), 都会挂靠到总线上
    那什么是挂靠到总线上呢?说白了就是建立三者之间的联系,比如device的数据结构中有一个指针指向bus跟driver,同理driver与bus也是一样的

  • 1.2 sysfs上的体现

  • 1.2.1在谈sysfs
    sysfs文件系统, 根据前面文章所讲的,体现给用户bus,device,driver的关系层(一目了然)
    大家都知道kset, kobject这些组成上层容器(bus, device, driver)的这些基类,他们的存在就是为了使这三者之间建立联系,并且通过sysfs向用户反映他们之间的联系,打个比方比如我插入Upan,内核检测到U盘插入后会调用device_add来添加设备,这里device_add会调用kobj_add会建立关系,所以你看。。

  • 1.2.2 bus的由来
    内核初始化的时候:
    start_kernel–>kernel_init(启动的一个内核线程)–>do_basic_setup–>driver_init
    在driver_init中:

	devices_init();buses_init();classes_init();

好的,上面就是这三座大山的初始化, 注意,这里还有个class_init,关于class的讲解,在下一篇文章会讨论
这里简单看一下devices_init()

	devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);if (!devices_kset)return -ENOMEM;dev_kobj = kobject_create_and_add("dev", NULL);if (!dev_kobj)goto dev_kobj_err;sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);if (!sysfs_dev_block_kobj)goto block_kobj_err;sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);if (!sysfs_dev_char_kobj)goto char_kobj_err;

这里不做过多解释,如果前面的文章都看了的话,相信这里的代码还是比较简单的
对于kset_create_and_add函数的作用前面有讲解:
三个init函数执行完之后,sysfs上的关系如下图所示:
这里写图片描述
摁,设备模型的骨架子基本上是出来了,之后我们看一下bus的数据结构

  • 1.2.3 bus_type
    上面讲到,在linux中真实总线与虚拟总线会被抽象出数据结构,即bus_type,下图会讲述一下bus_type中比较重要的参数
    这里写图片描述
    这里说一下bus_type中的match函数,对于每一个总线对应的match函数不同,比较简单的是platform总线
    platform_bus_init–>bus_register(&platform_bus_type);
    其中platform_bus_type
struct bus_type platform_bus_type = {.name		= "platform",.dev_attrs	= platform_dev_attrs,.match		= platform_match, //总线的match函数.uevent		= platform_uevent,.pm		= &platform_dev_pm_ops,
};

platform_match函数如下

static int platform_match(struct device *dev, struct device_driver *drv)
{struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);/* Attempt an OF style match first */if (of_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) == 0); //这里比较dev与drv的名字是否相等
}

上图中,重要的数据结构以及其作用已经很好的表达出来,接下来讨论下注册一个总线时都发生了什么
其实注册一个总线就是形成创建一个上图的关系网

  • 1.2.4注册一个总线(虽然现在没有注册总线的机会,但是有必要小研究一下)→bus_register
    我们采用这个方式,从代码中表示生成的步骤,之后用图来描述代码的步骤
    bus_register(&platform_bus_type):
int bus_register(struct bus_type *bus)
{int retval;struct subsys_private *priv;priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); //1.malloc ksubsys_private结构 if (!priv)return -ENOMEM;priv->bus = bus; //2.确立关系bus->p = priv;  //2.与bus确立暧昧关系BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//3.设置obj名字之后会在sysfs显示,因为sysfs显示的是obj的名字,所以用的bus->name,如上面显示, bus->name为platformif (retval)goto out;priv->subsys.kobj.kset = bus_kset;//4.确立与/sys/bus的关系priv->subsys.kobj.ktype = &bus_ktype;priv->drivers_autoprobe = 1;//5.为了加设备后自动添加驱动用retval = kset_register(&priv->subsys); //6.前面的准备做好后,注册近kobj机制中if (retval)goto out;retval = bus_create_file(bus, &bus_attr_uevent);//7.在/sys/bus/platform生成文件 ueventif (retval)goto bus_uevent_fail;priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj); //8.创建devicesif (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);//9.创建 driversif (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);retval = add_probe_files(bus);//10.创建drivers_probe, drivers_autoprobe文件if (retval)goto bus_probe_files_fail;retval = bus_add_attrs(bus);//11.如果bus中还定义了其他的属性文件,则创建if (retval)goto bus_attrs_fail;pr_debug("bus: '%s': registered\n", bus->name);return 0;bus_attrs_fail:remove_probe_files(bus);
bus_probe_files_fail:kset_unregister(bus->p->drivers_kset);
bus_drivers_fail:kset_unregister(bus->p->devices_kset);
bus_devices_fail:bus_remove_file(bus, &bus_attr_uevent);
bus_uevent_fail:kset_unregister(&bus->p->subsys);
out:kfree(bus->p);bus->p = NULL;return retval;
}

10来个步骤,还是比较清晰,下面跟一个图。。。(本人喜欢用图来说明问题,理清思路)
这里写图片描述
好了,对于bus的注册就讲完了, 下面开讲device_add这个函数,即,往总线添加一个设备都干嘛了,对于加入一个驱动的话同加入设备大同小异了,就不用再细说,老规矩,先分析代码,后根据上面的图进行延伸

  • 1.2.5注册设备(device_add)
    当然不同的平台对应不同的device结构,但是里面都会嵌入一个struct device结构
    这里我们以platform_device为例子,给出数据结构,呜哈哈
    这里写图片描述
    上图中 dev结构体里面的platform_data是特殊针对,下面我们看一下如何注册一个platform device
static struct platform_device leds_gpio = {.name	= "xxx_platDev_ma", //定义设备名字.id	= -1, //id初始化.dev	= {.platform_data	= NULL,//啥都不说了,dev的一个变量},
};

调用函数platform_device_register(&leds_gpio);
接下来,厉害了!重点介绍一下platform注册都发生了什么,想想都让人兴奋,GO!
当然,不能涉及到所有的细节,我们还是强调脉络的分析
这里写图片描述
大致的脉络已经体现出来了,至于其他的什么链接文件什么的,个人认为不是什么重点,所以在下面会从现象分析,东西实在太多,接下来我们还是跟据图还说明问题,形象的从图的角度看看都发生了什么,首先,来一个简单的例子

static struct platform_device leds_gpio = {.name	= "xx_platDev_ma",.id	= -1,.dev	= {.platform_data	= NULL},
};
struct class *ma_class = NULL;
struct device *dev1;
struct device *dev2;
struct device *dev3;
struct device *dev4;static int ma_class_init(void)
{int err;printk(KERN_ALERT "class_init\n");err = platform_device_register(&leds_gpio); //非常简单,就是注册一个名字为xx_platDev_ma的platform设备return 0;
}static void ma_class_exit(void)
{printk(KERN_ALERT "Goodbye, class_init\n");platform_device_unregister(&leds_gpio);
}module_init(ma_class_init);
module_exit(ma_class_exit);

我们结合上面的代码逻辑,给出小例子的图解分析
这里写图片描述
我们将例子insmod后,出现
这里写图片描述
我们看到/sys下的结构,跟上面分析的一致,摁。。基本上加入一个设备的分析到位了
还差个驱动的绑定,还的继续努力!
1.2.6驱动的绑定,关于这个方面,留个悬念,这里不想说的太多,老生长谈,大家有兴趣可以看下代码,对应的接口函数是bus_probe_device
在上面的1.2.3 中的图已经很清晰的介绍了绑定的流程顺序


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部