bus
来源:互联网 发布:剑网正太捏脸数据下载 编辑:程序博客网 时间:2024/04/29 07:08
"ls" 命令的 "-F" 命令为所列出的每个文件使用后缀来显示文件的类型,后缀 "/" 表示列出的是目录,后缀 "@" 表示列出的是符号链接文件。
1.bus定义
总线是不同IC器件之间相互通讯的通道;在计算机中,一个总线就是处理器与一个或多个不同外设之间的通讯通道;为了设备模型的目的,所有的设备都通过总线相互连接,甚至当它是一个内部的虚拟总线(如,platform总线);例如,设备模型表示在总线和它们控制的设备之间的实际连接;
Linux设备模型中,一个总线由内核结构体struct bus_type描述;其结构定义如下:
struct bus_type
{
const char* name; //总线类型的名称
struct subsystem subsys; //该总线所属的子系统subsystem,代表自身---kset
struct kset drivers; //该总线所使用的驱动程序的集合
struct kset devices; //挂接在该总线上的所有设备的集合
struct klist klist_devices; //挂接在该总线上的所有设备所组成的链表
struct klist klist_drivers; //该总线所使用的驱动程序所组成的链表
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, char** envp, int num_envp, char* buffer, int buffer_size);
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 (*resume)(struct device* dev);
};
//其中重点看一下私有成员结构体:
struct bus_type_private {
struct kset subsys; //bus内嵌的kset,代表其自身
struct kset *drivers_kset;
struct kset *devices_kset;
struct klist klist_devices; //包含devices链表及其操作函数
struct klist klist_drivers; //driver链表及其操作函数
struct blocking_notifier_head bus_notifier;
unsigned int drivers_autoprobe:1; //匹配成功自动初始化标志
struct bus_type *bus;
};
每个bus_type对象都对应/sys/bus目录下的一个子目录,如,PCI总线对应于/sys/bus/pci目录;在每个这样的子目录下存在两个子目录:devices和drivers,分别对应于bus_type结构中的devices和drivers成员,其中,devices子目录描述的是连接在该总线上的所有设备,drivers子目录描述的是该总线所使用的所有驱动程序;/sys/bus目录下的所有子目录都类似;
2.bus初始化和注册
bus的注册在/drivers/base/bus.c里
int __init buses_init(void)
{
bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
return 0;
}
bus_uevent_ops,这是一个uevent的操作集。
struct kset *kset_create_and_add(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
//传递进来的参数为("bus", &bus_uevent_ops, NULL)
{
struct kset *kset;
int error;
//创建一个kset容器
kset = kset_create(name, uevent_ops, parent_kobj);
//注册创建的kset容器
error = kset_register(kset);
return kset;
}
首先需要创建一个kset容器
static struct kset *kset_create(const char *name,
struct kset_uevent_ops *uevent_ops,
struct kobject *parent_kobj)
//传递进来的参数为("bus", &bus_uevent_ops, NULL)
{
struct kset *kset;
//为kset分配内存
kset = kzalloc(sizeof(*kset), GFP_KERNEL);
//设置kset中kobject的名字,这里为bus
kobject_set_name(&kset->kobj, name);
//设置uevent操作集,这里为bus_uevent_ops
kset->uevent_ops = uevent_ops;
//设置父对象,这里为NULL
kset->kobj.parent = parent_kobj;
//设置容器操作集
kset->kobj.ktype = &kset_ktype;
//设置父容器
kset->kobj.kset = NULL;
return kset;
}
//将kset添加到/sys中
int kset_register(struct kset *k)
{
int err;
//初始化
kset_init(k);
//添加该容器
err = kobject_add_internal(&k->kobj);
kobject_uevent(&k->kobj, KOBJ_ADD);
return 0;
}
kset_init进行一些固定的初始化操作,里面没有我们需要关心的内容
kobject_add_internal为重要的一个函数,他对kset里kobj的从属关系进行解析,搭建正确的架构
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
//检测kobj是否为空
if (!kobj)
return -ENOENT;
//检测kobj名字是否为空
if (!kobj->name || !kobj->name[0]) {
pr_debug("kobject: (%p): attempted to be registered with empty "
"name!\n", kobj);
WARN_ON(1);
return -EINVAL;
}
//提取父对象
parent = kobject_get(kobj->parent);
/* join kset if set, use it as parent if we do not already have one */
//父容器存在则设置父对象
if (kobj->kset) {//在bus的kset中为空,所以不会进入到下面的代码
//检测是否已经设置父对象
if (!parent)
//无则使用父容器为父对象
parent = kobject_get(&kobj->kset->kobj);
//添加该kobj到父容器的链表中
kobj_kset_join(kobj);
//设置父对象
kobj->parent = parent;
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
//建立相应的目录
error = create_dir(kobj);
kobj->state_in_sysfs = 1;
return error;
}
至此bus的目录就建立起来了
int bus_register(struct bus_type *bus)
{
int retval;
struct bus_type_private *priv;
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);//进入时bus_type->bus_type_private为NULL
if (!priv) //该函数主要是对其的设置
return -ENOMEM;
priv->bus = bus; //私有成员的bus回指该bus
bus->p = priv; //初始化bus->p,即其私有属性
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //设置该bus的名字,bus是kset的封装//bus_kset即为所有bus的总起始端点 //围绕bus内嵌的kset初始化,和kset的初始化时围绕
priv->subsys.kobj.kset = bus_kset; //kobj相似,没有parent时,就会用kset的kobj,此处即是
priv->subsys.kobj.ktype = &bus_ktype; //属性操作级别统一为bus_ktype
priv->drivers_autoprobe = 1;//设置该标志,当有driver注册时,会自动匹配devices
//上的设备并用probe初始化,当有device注册时也同样找到 driver并会初始化
retval = kset_register(&priv->subsys); //注册kset,创建目录结构,以及层次关系
retval = bus_create_file(bus, &bus_attr_uevent); //当前bus目录下生成bus_attr_uevent属性文件
if (retval)
goto bus_uevent_fail;
priv->devices_kset = kset_create_and_add("devices", NULL,//初始化bus目录下的devices目录,里面级联了该bus下设备,
&priv->subsys.kobj); //仍然以kset为原型
priv->drivers_kset = kset_create_and_add("drivers", NULL, //初始化bus目录下的drivers目录,里面级联了该bus下设备的driver
&priv->subsys.kobj);
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);//初始化klist_devices里的操作函数成员
klist_init(&priv->klist_drivers, NULL, NULL); //klist_drivers里的操作函数置空
retval = add_probe_files(bus); //增加bus_attr_drivers_probe和bus_attr_drivers_autoprobe
retval = bus_add_attrs(bus); //增加默认的属性文件
}
3.bus属性
struct bus_attribute
{
struct attribute attr;
ssize_t (*show)(struct bus_type* bus, char* buf);
ssize_t (*store)(struct bus_type* bus, const char* buf, size_t count);
};
int bus_create_file(struct bus_type* bus, struct bus_attribute* attr):为指定总线添加属性;
void bus_remove_file(struct bus_type* bus, struct bus_attribute* attr):删除指定总线上的指定属性;
- bus
- BUS
- bus
- D-BUS
- D-BUS
- Message Bus
- D-BUS
- Platform bus
- I2C Bus
- Bus System
- CAN-BUS
- PCI Bus
- Local Bus
- CXF BUS
- bus基础知识
- bus hound
- Bus Route
- Bus Error
- SAP 表的种类
- jQuery Mobile 新手上路--引用顺序
- kset
- 13.select语句
- 机房收费系统之不同用户系别享有不同权限
- bus
- vc、gcc虚继承内存布局
- div+css制作简易相册代码
- android中跳转系统自带界面
- 14.Oracle的操作符
- driver
- 解析PHP中 传值、传引用、传地址之区别
- DM8168自动登录与开机运行程序
- device