Linux设备模型
1
• 1、什么是设备模型,为什么使用设备模型?
• 2、设备模型的基础结构体?
• 3、sysfs副产品
• 4、建立在模型之上的bus/device/driver
2
1、什么是设备模型?
• 用统一的结构体①,将设备组织为树形拓
扑结构②,实现多种便利性能③的方法.
• 统一的结构体①: • 统一的结构体①:
Structkobject{}, structkset{}, structktype{}
• 树形拓扑结构②
3
• root@s3lite:/ # lssys
-lssys
-block
-loop0
-loop1
-loop2
…
-bus
-class
-android_usb
-arvo -arvo
-audio
…
-dev
-devices
-firmware
-fs
-kernel
4
• 实现多种便利性能③
–1)代码重复最小化
–2)提供统一的机制
–3)以树的形式组织设备/总线,方便查看所有设备
–4)方便联系总线/设备/驱动
–5)方便设备归类,管理
–6)可沿设备数子节点向上依次遍历,保证正确顺序关
闭电源(有些文档说这是设计设备模型的初衷) 闭电源(有些文档说这是设计设备模型的初衷)
–顺序关闭设备的重要性?:主从关系,比如usbhost,u
盘slave,先关闭host,那么u盘仍然是供电的,但是这
个耗电是没有意义的
5
2、设备模型的基础结构体?
• 1)
structkobject{
• const char *name; //kobj有自己的名字
• structlist_head entry; //kobject结构链表
• struct kobject *parent;//有个parent struct kset
*kset; //指向kset集合 *kset; //指向kset集合
• structkobj_type*ktype; //有个ktype
• structsysfs_dirent *sd; //sysfs文件目录
• struct kref kref; //引用计数,跟踪对象生命周期,引用
为0,结束
• unsigned intstate_initialized:1;
• unsigned intstate_in_sysfs:1;
• unsigned intstate_add_uevent_sent:1;
• unsigned intstate_remove_uevent_sent:1;
• unsigned intuevent_suppress:1;
};
6
• Kobject的特点
1)一般不会单独使用,没多大意义(创建目录结构),主
要是嵌入在具体的设备结构体中,用来实现设备模型。
2)kobject为什么可以实现设备模型,为什么使用kobject
来实现设备模型?
(1)有name,有嵌入的的parent,可以实现树形结构
(2)有和sysfs对应的目录入口sysfs_dirent,用来实现文
件抽象
3)使用kref来监测kobject的生命周期。为什么使用kref,
kref存在的意义?
(1)两个模块同时使用一个结构体,eg. 子设备指向父
设备,如果父设备在子设备之前被释放,那么就会出
现空指针问题
7
• Kobject操作函数
intkobject_init_and_add(struct kobject*kobj, struct kobj_type
*ktype,structkobject*parent, const char *fmt, ...) //add driver ???
{
kobject_init(kobj, ktype);//初始化kobj的ktype为parent_ktype
retval= kobject_add_varg(kobj, parent, fmt, args);
}
intkobject_add(struct kobject*kobj, struct kobject*parent,const
char *fmt, ...) //add device ???
{
retval= kobject_add_varg(kobj, parent, fmt, args);
}
8
• struct kobject*kobject_get(struct kobject*kobj)
• void kobject_put(struct kobject*kobj)
• /**
• * kobject_del-unlink kobjectfrom hierarchy.
• * @kobj: object.
• */
• void kobject_del(struct kobject*kobj)
• intkobject_uevent(&dev->kobj, KOBJ_ADD);
9
• 2)
struct kobj_type{
• void (*release)(struct kobject*kobj);//释放函数(驱动编写时提供),此
函数会被kobject_put函数调用
• const struct sysfs_ops*sysfs_ops; //属性文件的操作函数(只有读和写操
作)
• structattribute **default_attrs;
• const structkobj_ns_type_operations*(*child_ns_type)(structkobject
*kobj); *kobj);
• const void *(*namespace)(structkobject*kobj);
};
10
•3)
struct kset{
structlist_headlist; //连接该kset中所有kobject的链表头
spinlock_tlist_lock;
struct kobjectkobj;
const structkset_uevent_ops*uevent_ops;};
};
kset是嵌入到相同类型结构的kobject集合。Kset也可以看
作一个kobject,一旦一个kset被建立,sysfs就会创建的目
录给他
11
• Uevent(user space event)
• Kobject创建完成,会发送uevent事件到user space,user space继续完成其他
操作>> udev。
• 事件类型
• enumkobject_action
{
KOBJ_ADD = (__force kobject_action_t) 0x01, //exclusive to core
KOBJ_REMOVE= (__force kobject_action_t) 0x02, //exclusive to core
KOBJ_CHANGE= (__force kobject_action_t) 0x03, //device state change
KOBJ_REMOVE= (__force kobject_action_t) 0x02, //exclusive to core
KOBJ_CHANGE= (__force kobject_action_t) 0x03, //device state change
KOBJ_MOUNT = (__force kobject_action_t) 0x04, //mount event for block
KOBJ_UMOUNT= (__force kobject_action_t) 0x05, //umountevent for block
KOBJ_OFFLINE = (__force kobject_action_t) 0x06, //device offline
KOBJ_ONLINE= (__force kobject_action_t) 0x07, //device online
};
• Uevent本质是netlink消息--socket
12
• enumkobject_action
{
KOBJ_ADD = (__force kobject_action_t) 0x01, //exclusive to core
KOBJ_REMOVE= (__force kobject_action_t) 0x02, //exclusive to core
KOBJ_CHANGE= (__force kobject_action_t) 0x03, //device state change
KOBJ_MOUNT = (__force kobject_action_t) 0x04, //mount event for block devices (bro
KOBJ_UMOUNT= (__force kobject_action_t) 0x05, //umountevent for block devices (b
KOBJ_OFFLINE = (__force kobject_action_t) 0x06, //device offline
KOBJ_ONLINE= (__force kobject_action_t) 0x07, //device online
};
13
• Kset与ktype的区别
• 都是kobject的集合,但是,kset是kobject个体集合,ktype
是kobject属性集合。
一个ktype可以分为多种kset;
一个kset只属于一个ktype
14
15
kobj_type
16
3、sysfs
• sysfs----一个虚拟的文件系统。sysfs给用户提供了一个从用
户空间去访问内核设备的方法,它在Linux里的路径是/sys。
这个目录并不是存储在硬盘上的真实的文件系统,只有在
系统启动之后才会建起来。
1、Sysfs的目录/文件创建
• 在kobject创建的时候,对应sysfs的目录就已经创建了
17
create_dir(kobj)
kobject_add_internal
kobject_add_varg
create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd)
sysfs_create_dir(kobj)
18
1)
structkobj_type{
conststructsysfs_ops*sysfs_ops;
structattribute**default_attrs;
}
2)
structkobj_attribute{
structattributeattr;
ssize_t(*show)(structkobject*kobj, structkobj_attribute*attr, char*buf); ssize_t(*show)(structkobject*kobj, structkobj_attribute*attr, char*buf);
ssize_t(*store)(structkobject*kobj, structkobj_attribute*attr, constchar*buf, size_t
};
structdevice_attribute
structbus_attribute
structclass_attribute
structdriver_attribute
…..
….. 19
• staticDEVICE_ATTR(dpdm_pulldown_enable, S_IRUGO |
S_IWUSR, 4386 dpdm_pulldown_enable_show,
dpdm_pulldown_enable_store);
• #defineDEVICE_ATTR(_name,_mode,_show,_store)
structdevice_attributedev_attr_##_name = \
__ATTR(_name,_mode,_show,_store)
• device_create_file(&pdev->dev,
&dev_attr_dpdm_pulldown_enable);
20
4、建立在模型之上的
bus/device/driver
• 1)Bus结构体
21
• struct bus_type{
• const char *name;
• const char *dev_name;
• struct device *dev_root;
• struct bus_attribute *bus_attrs;
• struct device_attribute*dev_attrs;
• struct driver_attribute *drv_attrs;
• 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_tstate);
• int(*resume)(struct device *dev);
• const struct dev_pm_ops*pm;
• struct iommu_ops*iommu_ops;
• struct subsys_private*p;
• }
22
• struct subsys_private{
• struct ksetsubsys; //这个是subsys自身的kset
• struct kset*devices_kset; //这个是这个subsys上的device树
• struct list_head interfaces;
• struct mutexmutex;
• struct kset*drivers_kset; //这个是这个subsys上的driver树
• struct klistklist_devices; //设备链表
• struct klistklist_drivers; //驱动链表
• struct blocking_notifier_headbus_notifier; • struct blocking_notifier_headbus_notifier;
• unsigned intdrivers_autoprobe:1;
• struct bus_type*bus; //回指bus_type
• struct ksetglue_dirs;
• struct class *class;
• };
23
• struct device {
• struct device *parent;
• struct device_private *p; //私有数据
• struct kobjectkobj;
• const char *init_name; /* initial name of the device */
• const struct device_type*type;
• struct bus_type *bus; /* type of bus device is on */
• struct device_driver*driver; /* which driver has allocated this device*/
• u64 *dma_mask; /* dmamask (if dma'abledevice) */
• u64 coherent_dma_mask;/* Like dma_mask, but for
• dev_t devt; /* dev_t, creates the sysfs"dev" */ • dev_t devt; /* dev_t, creates the sysfs"dev" */
• u32 id; /* device instance */
• spinlock_t devres_lock;
• struct list_head devres_head;
• struct klist_node knode_class;
• struct class *class;
• const struct attribute_group**groups; /* optional groups */
• }
24
• struct device_private{
• struct klistklist_children; //子设备
• struct klist_nodeknode_parent;
• struct klist_nodeknode_driver;
• struct klist_nodeknode_bus;
• struct list_headdeferred_probe;
• void *driver_data; //指向driver数据
• struct device *device; //回指 • struct device *device; //回指
• };
25
• struct device_driver{
• const char *name;
• struct bus_type *bus; //所在总线
• struct module *owner;
• const char *mod_name; /* used for built-in modules */
• boolsuppress_bind_attrs; /* disables bind/unbind via sysfs*/
• const struct of_device_id *of_match_table;
• int(*probe) (struct device *dev); • int(*probe) (struct device *dev);
• int(*remove) (struct device *dev);
• void (*shutdown) (struct device *dev);
• int(*suspend) (struct device *dev, pm_message_tstate);
• int(*resume) (struct device *dev);
• const struct attribute_group**groups;
• const struct dev_pm_ops*pm;
• struct driver_private*p; //私有数据
• };
26
• struct driver_private{
• struct kobjectkobj; //driver对应的kobj
• struct klistklist_devices; //支持的设备链表
• struct klist_nodeknode_bus;
• struct module_kobject*mkobj;
• struct device_driver*driver; //回指
• };
27
28
bus_add_device(dev);
device_add
kernel_init-> customize_machine-> platform_add_devices
设备注册过程
bus_probe_device(dev); //一般找不到驱动
kobject_uevent
kobject_add; device_create_file; device_add_class_symlinks