最早在去年的時候學習MMC/SD/SDIO的時候就接觸過裝置驅動模型,但是當時也整天看書也是迷迷糊糊的,所以最終也沒有將這部分知識很好的整理一下。現在再次接觸到這部分知識。也算是完成一直以來的一個想法。把這部分知識簡單的整理一下備忘。
裝置驅動模型最初是為瞭解決裝置的電源管理而產生的,但是最後發展起來之後,作用就越來越大了,特別適合裝置管理。對於linux裝置驅動工程師來說,掌握裝置驅動模型非常重要。
linux的裝置驅動模型的底層機制主要包括:kobject,kobj_type,kset等幾個結構。這幾個結構定義在include/linux/kobject.h中。
kobject代表裝置驅動模型中一個基本對象。每個kobject都對應於sysfs中的一個目錄。上層結構例如device,device_driver,bus_type都嵌入了一個kobject,這相當於物件導向程式設計機制中的繼承機制。kobject的定義如下:
60 struct kobject { 61 const char *name;/*名稱*/ 62 struct list_head entry;/*用於鏈入所屬的kset的鏈表*/ 63 struct kobject *parent;/*父object*/ 64 struct kset *kset;/*所屬kset*/ 65 struct kobj_type *ktype;/*所屬ktype*/ 66 struct sysfs_dirent *sd;/*sysfs中的目錄項*/ 67 struct kref kref;/*生命週期(引用計數)管理*/ 68 unsigned int state_initialized:1;/*標記:初始化*/ 69 unsigned int state_in_sysfs:1;/*標記:在sysfs中*/ 70 unsigned int state_add_uevent_sent:1;/*標記:已發出KOBJ_ADD uevent*/ 71 unsigned int state_remove_uevent_sent:1;/*標記:已發出的KOBJ_REMOVE uevent*/ 72 unsigned int uevent_suppress:1;/*標記:禁止發出uevent*/ 73 };
kobject的基本操作:
76 int kobject_set_name(struct kobject *kobj, const char *name, ...); 77 extern int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, 78 va_list vargs); 79 80 static inline const char *kobject_name(const struct kobject *kobj) 81 { 82 return kobj->name; 83 } 84 85 extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype); 86 extern __printf(3, 4) __must_check 87 int kobject_add(struct kobject *kobj, struct kobject *parent, 88 const char *fmt, ...); 89 extern __printf(4, 5) __must_check 90 int kobject_init_and_add(struct kobject *kobj, 91 struct kobj_type *ktype, struct kobject *parent, 92 const char *fmt, ...); 93 94 extern void kobject_del(struct kobject *kobj); 95 96 extern struct kobject * __must_check kobject_create(void); 97 extern struct kobject * __must_check kobject_create_and_add(const char *name, 98 struct kobject *parent); 99 100 extern int __must_check kobject_rename(struct kobject *, const char *new_name);101 extern int __must_check kobject_move(struct kobject *, struct kobject *);102 103 extern struct kobject *kobject_get(struct kobject *kobj);104 extern void kobject_put(struct kobject *kobj);105 106 extern char *kobject_get_path(struct kobject *kobj, gfp_t flag);
kobj_type
kobj_type是kobject所屬的類型,定義了某種類型的kobject的公用屬性和操作。定義如下:
108 struct kobj_type {109 void (*release)(struct kobject *kobj);110 const struct sysfs_ops *sysfs_ops;111 struct attribute **default_attrs;112 const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);//Callbacks so sysfs can determine namespaces113 const void *(*namespace)(struct kobject *kobj);114 };
kset
kset是一個kobject集合(或容器),包含了一系列的kobject。需要注意的是,kset內部也嵌入了kobject,這表明kset本身也是一個kobject。kset的定義如下:
159 struct kset {160 struct list_head list;161 spinlock_t list_lock;162 struct kobject kobj;163 const struct kset_uevent_ops *uevent_ops;164 };
kset的基本操作:
166 extern void kset_init(struct kset *kset);167 extern int __must_check kset_register(struct kset *kset);168 extern void kset_unregister(struct kset *kset);169 extern struct kset * __must_check kset_create_and_add(const char *name,170 const struct kset_uevent_ops *u,171 struct kobject *parent_kobj);172 173 static inline struct kset *to_kset(struct kobject *kobj)174 {175 return kobj ? container_of(kobj, struct kset, kobj) : NULL;176 }177 178 static inline struct kset *kset_get(struct kset *k)179 {180 return k ? to_kset(kobject_get(&k->kobj)) : NULL;181 }182 183 static inline void kset_put(struct kset *k)184 {185 kobject_put(&k->kobj);186 }187 188 static inline struct kobj_type *get_ktype(struct kobject *kobj)189 {190 return kobj->ktype;191 }
上層的資料結構
這部分就是我們比較關注的裝置,驅動和匯流排了。linux2.6之後的核心中引入了新的裝置管理機制kobject,通過這個資料結構使所有的底層都具有統一的介面,Kobject提供基本的對象管理。它與sysfs檔案系統緊密關聯,每個核心中註冊的kobject對象對應於sysfs檔案系統中的一個目錄。kobject通常通過kset組織成層次化結構,kset是具有相同類型的kobject的集合。在這些核心對象機制的基礎上,linux的裝置模型(/include/linux/device.h)包括裝置結構devices、驅動結構drivers、匯流排結構buses、裝置類結構classes幾個關鍵組件。linux中的任一裝置在裝置模型中都由一個device對象描述,其對應的資料結構struct device定義為:
633 struct device {634 struct device *parent;635 636 struct device_private *p;637 638 struct kobject kobj;639 const char *init_name; /* initial name of the device */640 const struct device_type *type;641 642 struct mutex mutex; /* mutex to synchronize calls to643 * its driver.644 */645 646 struct bus_type *bus; /* type of bus device is on */647 struct device_driver *driver; /* which driver has allocated this648 device */649 void *platform_data; /* Platform specific data, device650 core doesn't touch it */651 struct dev_pm_info power;652 struct dev_pm_domain *pm_domain;653 654 #ifdef CONFIG_NUMA655 int numa_node; /* NUMA node this device is close to */656 #endif657 u64 *dma_mask; /* dma mask (if dma'able device) */658 u64 coherent_dma_mask;/* Like dma_mask, but for659 alloc_coherent mappings as660 not all hardware supports661 64 bit addresses for consistent662 allocations such descriptors. */663 664 struct device_dma_parameters *dma_parms;665 666 struct list_head dma_pools; /* dma pools (if dma'ble) */667 668 struct dma_coherent_mem *dma_mem; /* internal for coherent mem669 override */670 #ifdef CONFIG_CMA671 struct cma *cma_area; /* contiguous memory area for dma672 allocations */673 #endif674 /* arch specific additions */675 struct dev_archdata archdata;676 677 struct device_node *of_node; /* associated device tree node */678 679 dev_t devt; /* dev_t, creates the sysfs "dev" */680 u32 id; /* device instance */681 682 spinlock_t devres_lock;683 struct list_head devres_head;684 685 struct klist_node knode_class;686 struct class *class;/*所屬的類別*/687 const struct attribute_group **groups; /* optional groups */688 689 void (*release)(struct device *dev);690 };
device的基本操作
788 extern int __must_check device_register(struct device *dev);789 extern void device_unregister(struct device *dev);790 extern void device_initialize(struct device *dev);791 extern int __must_check device_add(struct device *dev);792 extern void device_del(struct device *dev);793 extern int device_for_each_child(struct device *dev, void *data,794 int (*fn)(struct device *dev, void *data));795 extern struct device *device_find_child(struct device *dev, void *data,796 int (*match)(struct device *dev, void *data));
device_driver
device_driver代表一個裝置驅動程式,對應於/sys/bus/xxx/drivers./下的一個目錄。定義如下:
215 struct device_driver {216 const char *name;/*名稱*/217 struct bus_type *bus;/*匯流排*/218 219 struct module *owner;/*所有者*/220 const char *mod_name; /* used for built-in modules */221 222 bool suppress_bind_attrs; /* disables bind/unbind via sysfs */223 224 const struct of_device_id *of_match_table;225 /*操作裝置的方法*/226 int (*probe) (struct device *dev);227 int (*remove) (struct device *dev);228 void (*shutdown) (struct device *dev);229 int (*suspend) (struct device *dev, pm_message_t state);230 int (*resume) (struct device *dev);231 const struct attribute_group **groups;/*屬性群組*/232 233 const struct dev_pm_ops *pm;/*電源管理*/234 235 struct driver_private *p;236 };
bus_type
bus_type代表一個匯流排,對應於/sys/bus/下的一個目錄。定義如下:
90 struct bus_type { 91 const char *name; 92 const char *dev_name; 93 struct device *dev_root; 94 struct bus_attribute *bus_attrs;/*匯流排屬性*/ 95 struct device_attribute *dev_attrs;/*裝置預設屬性*/ 96 struct driver_attribute *drv_attrs;/*驅動預設屬性*/ 97 /*對裝置和驅動的操作方法*/ 98 int (*match)(struct device *dev, struct device_driver *drv); 99 int (*uevent)(struct device *dev, struct kobj_uevent_env *env);100 int (*probe)(struct device *dev);101 int (*remove)(struct device *dev);102 void (*shutdown)(struct device *dev);103 104 int (*suspend)(struct device *dev, pm_message_t state);105 int (*resume)(struct device *dev);106 107 const struct dev_pm_ops *pm;108 109 struct iommu_ops *iommu_ops;110 111 struct subsys_private *p;112 };
match()方法用於判斷掛在匯流排下的某個device和某個device_driver是否匹配,在一個device或一個device_driver註冊到匯流排上時調用。uevent()方法用於為uevent機制添加環境變數,在處理uevent時被調用。其他方法都是操作匯流排上掛接的device的。probe(),remove().shutdown(),resume()這幾個方法在device_driver中也定義了。核心在調用這些方法時,會優先調用bus_type中定義的方法。如果相應的方法在bus_type中未定義,才會調用device_driver中定義的方法。bus_type的基本操作:
122 extern int __must_check bus_register(struct bus_type *bus);123 extern void bus_unregister(struct bus_type *bus);124 125 extern int __must_check bus_rescan_devices(struct bus_type *bus);126 127 /* iterator helpers for buses */128 struct subsys_dev_iter {129 struct klist_iter ki;130 const struct device_type *type;131 };132 void subsys_dev_iter_init(struct subsys_dev_iter *iter,133 struct bus_type *subsys,134 struct device *start,135 const struct device_type *type);136 struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter);137 void subsys_dev_iter_exit(struct subsys_dev_iter *iter);138 139 int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data,140 int (*fn)(struct device *dev, void *data));141 struct device *bus_find_device(struct bus_type *bus, struct device *start,142 void *data,143 int (*match)(struct device *dev, void *data));144 struct device *bus_find_device_by_name(struct bus_type *bus,145 struct device *start,146 const char *name);147 struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id,148 struct device *hint);149 int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,150 void *data, int (*fn)(struct device_driver *, void *));
bus_type、device和device_driver之間的關係
bus_type相當於一個容器,是device和device_driver的管理機構,它包含了一個device集合(kset)和一個device_driver集合(kset),分別表示掛在匯流排下的所有裝置和所有裝置驅動程式。
device_driver掛在某個bus_type下面,包含了一個device集合(kset),表示這個驅動程式操作(或控制)的所有裝置。device_driver還包含了一個bus_type指標,表示驅動程式所在的匯流排。
device掛在某個bus_type下面,包含了一個device_driver指標,表示這個裝置對應的裝置驅動程式。device還包含一個bus_type指標,表示裝置所在的匯流排。
需要說明的是,一個實際的匯流排在裝置驅動模型中是用兩個結構表示的:bus_type和device。bus_type代表匯流排類型,出現在/sys/bus/目錄下;device代表匯流排裝置,出現在/sys/devices/目錄下,這表明實際的匯流排本質上是一種裝置。
/**
* 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 subsys_private *priv;
priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->bus = bus;
bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);