linux 驱动入门5

慢慢的开始转驱动,目前比较有时间,必定要把驱动学会。哎。人生慢慢路,一回头。已经工做了八九年了。努力。在买套房。改退休了。学驱动。我的认为首先要熟悉驱动框架。慢慢来。心急吃不了热豆腐。编程

看网上都说的设备是挂在总线的。固然硬件布线是这样的。软件也是模拟了这个过程。那总线是如何组织的呢。其实能够看到。闭环。闭环。双向闭环链表。 对。全部的设备是个闭环链表。全部的总线也是
闭环链表。那这些总线是如何造成这个闭环链表的呢?框架

这就是以党中央为中心,牢牢的团结围绕在党中央周围。换句话就是,以bus.c为中心。其余各类i2c, usb, platform牢牢的围绕在他的周围。那是如何围绕的呢。既然是链表,只要抓住表头,就能够了。因此bus.c为中心。其余各类i2c
定义了表头,其余总线不断加入这个环了。模块化

关于这个环结构。这个相对花点时间能够看明白。也就是kset kobject的关系。这个网上太多了。就不必说了。函数

那下面咱们分析下。各类具体的总线是如何挂到了bus.c的聊表头里的。spa

在device.h中
/* This is a #define to keep the compiler from merging different
* instances of the __key variable */
#define bus_register(subsys) \
({ \
static struct lock_class_key __key; \
__bus_register(subsys, &__key); \ // marvell, honeywell 臧春杰
})debug

哎,就它,全部的具体总线都要经过它来挂到链表里。就像platform.c里
int __init platform_bus_init(void)
{
int error;指针

early_platform_cleanup();orm

error = device_register(&platform_bus);
if (error)
// marvell, honeywell 臧春杰
return error;
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
return error;
}
都是这样注册的。对象

那下面咱们具体分析注册过程。很差整。看内核代码,须要对c比较熟悉。对模块化编程方法比较熟悉。进程

这样就进到了int __bus_register(struct bus_type *bus, struct lock_class_key *key)
传进的参数都是bus_type. 看看这个结构体,很大。很吓人。可是若是实现某个具体总线。却设置的变量很少。咱们能够看到subsys_private这个,这个为何叫private呢? 在面向对象里。private是私有的。
莫非有什么特殊含义。个人我的理解是,这样的结构体不须要外围模块操做。也就是不须要platform.c操做。这个东西会有bus.c内部处理。

果真能够看到,进到函数里。来了这样一句
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); // marvell, honeywell 臧春杰
priv->bus = bus;
bus->p = priv;
看来真的不要具体总线模块操做。即便你真的写了值了。那块内存也是垃圾内存。这里会重新分配操做。嗯。

retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;

priv->subsys.kobj.kset = bus_kset;
// marvell, honeywell 臧春杰
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;

retval = kset_register(&priv->subsys);

这几句须要和起来,完成了动做。操做subsys的kobj, 由于kset进程之kobject. 也就是kobject是kset的成员。 看来,熟悉kset kobject的关系相当重要。因此,这个是基础,必定得熟悉,否则无法整。

对kobj设置名字。 指定kobj的所属kset. 也就是kobje属于哪一个环,要把kobj加到kset链表,全靠这个指定。下面对kobj的ktype ,也就是指定kobj的属性,和属性操做方法。操做方法? 什么操做方法。

属性attribute对应的sysfs的文件, sysfs_ops就是对这些属性文件作show store后的实现方法。

这里,这个ops和这个kobj绑定上了。那全部对这个kobj的属性的读写都是有ops来处理。对。是这样的。

下面一句是保存值,之后对属性副职。

把内存初始化完后,下面就改真正的挂到聊表里了。前面只是对内存操做。kset_register,经过这个函数,就是把subsys的kobj加// marvell, honeywell 臧春杰到了bus_kset这个连表头里了。哪这个bus_kset这个东西哪里呢?

这是在bus.c初始化的时候建立的。因此各个模块初始化的时候不是胡乱的。有书序的。经过各类initcall把函数指针加到对应的初始化段里。分7个段。也就是7级。从1级慢慢初始化。 至关于7个堆栈。每一个栈有不少的函数指针。

一个栈就是一级。以及一级的来初始化。

全部,bus.c的初始化
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", // marvell, honeywell 臧春杰*/&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_kset.

这样register后,具体的总线结构体就挂到了总线链表头了。

retval = bus_create_file(bus, &bus_attr_uevent);
这句就是在sysfs建立了文件, // marvell, honeywell 臧春杰 文件名和权限都有bus_attr_uevent决定。对了。这个结构体就是
static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);

这就是这个结构体定义。文件名uevent. 咱们能够在/sys/bus/platform下有个uevent文件--w------- root root 4096 1970-01-01 17:04 uevent 看到没,文件名和权限是否是对的。

priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}

priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);

下面就是这两句了。没什么,就是建立了两个kset结构体。咱们主要看到了两个字符串。devices, drivers这个没什么奇怪,他会生成两个目录,真的生成了吗? 确实有
drwxr-xr-x root root 1970-01-01 17:04 devices
drwxr-xr-x root root 1970-01-01 17:04 drivers
// marvell, honeywell 臧春杰
-rw-r--r-- root root 4096 1970-01-01 17:04 drivers_autoprobe
--w------- root root 4096 1970-01-01 17:04 drivers_probe
--w------- root root 4096 1970-01-01 17:04 uevent
真的有,它是何时,生成的呢? 如何生成的呢? 就是在kobj注册的时候,虽然这里的kobj的kset位null. 可是进入kobject.c里,咱们看到error = create_dir(kobj);对,就是在这里建立了这两个目录。

此时有个疑问,文件夹的名字知道了。那系统如何知道该放到这里呢? sysfs的目录放到哪里取决于parent。这里能够看到parent就是platform的subsys的kobj。 因此就放到这了。

INIT_LIST_HEAD(&priv->interfaces);
__mutex_init(&priv->mutex, "subsys mutex", key);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
// marvell, honeywell 臧春杰
klist_init(&priv->klist_drivers, NULL, NULL);

retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;

retval = bus_add_attrs(bus);
if (retval)
goto bus_attrs_fail;

pr_debug("bus: '%s': registered\n", bus->name);
return 0;

下面这几句都同样了。都是建立了sysfs的文件,关联上show store处理函数。值得一提的是 klist_init这里初始化后,就为了把device driver挂到这上面。具体device driver如何挂总线上,咱们后续说。

先把bus.c分析I明白了。一个个来。不着急。

那这样bus.c的总线注册函数就分析完了。