在前面學習了 kobject和 kset之後,就迫不及待的想開始“研究”設備模型了。經過這幾天的學習,感覺受益匪淺。所以就將自己的理解整理了下來
想要完成一個設備的驅動,就要涉及三部分: Bus, device, driver。當然這些“新”節點都是最終繼承於kobject。
一.Bus
這裡先整理一下BUS,總線負責在設備與驅動間建立連接,包括 I2C, PCI, 串口,platform等。其中platform是虛擬總線。
1.1 結構體
信息結構體是 bus_type.
struct bus_type {
const char *name; //the name of bus
struct bus_attribute *bus_attrs;
//attribute for bus, contain attribute file and some operate function.
// this is a interface between kernel space and user space.
struct device_attribute *dev_attrs; //attribute for device,
struct driver_attribute *drv_attrs; //attribute for deriver
int (*match)(struct device *dev, struct device_driver *drv);
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
int (*probe)(struct device *dev);
int (*remove)(struct device *dev);
void (*shutdown)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*suspend_late)(struct device *dev, pm_message_t state);
int (*resume_early)(struct device *dev);
int (*resume)(struct device *dev);
struct dev_pm_ops *pm; //power manage
struct bus_type_private *p;
//private data for bus. In fact, it is core of this structure
};
在其中 bus_attrs, dev_attrs 和 drv_attrs記錄了該總線的一些屬性信息,而最重要的被用來構建該總線的邏輯結構的信息都記錄在了bus_type_private中。對應這個總線私有數據結構體的解析如下。
struct bus_type_private {
struct kset subsys;
//there are two points:
//1).this is a set. It is contain some devices and derivers about this bus.
//2). it's parent is @bus_kset, which is the root of all other bus.@bus_kset have many subset, this is just one of them.
//
struct kset *drivers_kset;
//all drivers about this bus will belong to this set.
struct kset *devices_kset;
//all devices of this bus will belong to this set.
struct klist klist_devices;
struct klist klist_drivers;
//they are two lists , for mount all corresponding nodes.
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1;
//is this bus automaticly run when a new devices arrvied.
//sometime, we can see some attribute files in user space.(for example:@drivers_autoprobe).
//it is interface that kernel leave user to modify this argument.
struct bus_type *bus;
//just a port for return this bus.
};
其中的klist_devices, klist_drivers 鏈表會用來掛載該總線的設備與驅動。當需要找東西的時候就會去倆面翻。而上面的兩個kset 分別是它們所屬的集合。不同的集合對應於不同的操作特性。這是一種很給力的組織結構。就拿這裡來說,我們用kobject來組織了一個二維鏈表(或其他什麼數據結構),每個kobject在這個鏈表中充當了一個節點。但又想讓其中指定的一些kobject節點具有一些屬性。kset相當於kobject的屬性。它包含了進行事件通知需要的一些數據信息。每當kobject有需要時,就會去找到自己所屬的kset,或者上級kobject的kset來用。
1.2 重要函數分析
對於總線的注冊需要使用到如下函數,通過分析它的行為對於理解bus_type的邏輯結構是很有幫助。
/**
* bus_register - register a bus with the system.
* @bus: bus.
*
* Once we have that, we registered the bus with the kobject
* infrastructure, then register the children subsystems it has:
* the devices and drivers that belong to the bus.
*/
int bus_register(struct bus_type *bus)
{
int retval;
struct bus_type_private *priv;
//alloc a private data package for @bus. It is the core of this structure,
//include device list, deriver list and so on.
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
// before we keep on, what we should to know is that this bus is one of members of the great building,
//so it must be inherit form @kobject.
//and @(priv->subsys.kobj) is it's kobject.
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
priv->subsys.kobj.kset = bus_kset; //1).@bus_kset is the root of all buses. 2). this structure is the type of bus.
priv->subsys.kobj.ktype = &bus_ktype; //corresponding operation function for bus
priv->drivers_autoprobe = 1; //automaticly probe when new device arrived.
retval = kset_register(&priv->subsys);
if (retval)
goto out;
retval = bus_create_file(bus, &bus_attr_uevent); //create attribute file for bus,it is a interface between user space and kernel space.
if (retval)
goto bus_uevent_fail;
//給該總線創建一個設備子集,it is the set of all devices about this bus.
//在文件系統中的表現就是在該總線的目錄下多了一個名字叫"devices"的子目錄
//還需要提醒的一點就是:設備模型中的層次結構關系都是由kobject對象來指定,所以凡是屬於這個設備模型的節點必須要繼承kobject.
priv->devices_kset = kset_create_and_add("devices", NULL,
&priv->subsys.kobj);
if (!priv->devices_kset) {
retval = -ENOMEM;
goto bus_devices_fail;
}
//create a deriver set for this bus
priv->drivers_kset = kset_create_and_add("drivers", NULL,
&priv->subsys.kobj);
if (!priv->drivers_kset) {
retval = -ENOMEM;
goto bus_drivers_fail;
}
//thoes two list is used to mount some nodes. device-node or deriver-node.
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&priv->klist_drivers, NULL, NULL);
//create attribute file for this structure
retval = add_probe_files(bus);
if (retval)
goto bus_probe_files_fail;
retval = bus_add_attrs(bus); //create attribute file for @bus_attr
if (retval)
goto bus_attrs_fail;
pr_debug("bus: '%s': registeredn", 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);
kfree(bus->p);
out:
bus->p = NULL;
return retval;
}
在函數體中已經對行為進行了較詳細的分析。
1.3 device_bind_driver
那麼device到底又是怎麼和一個driver進行綁定的呢?讓它們在需要時能找到彼此
//bind a driver to one device.
int device_bind_driver(struct device *dev)
{
int ret;
ret = driver_sysfs_add(dev);
if (!ret)
driver_bound(dev);
return ret;
}
//這個函數是在設備已經綁定驅動之後使用,
static voi