-
二、linux设备模型层次关系:bus_type,device,device_driver
-
-
驱动核心可以注册多种类型的总线。
-
每种总线下面可以挂载许多设备。(通过kset devices)
-
每种总线下可以用很多设备驱动。(通过包含一个kset drivers)}
-
每个驱动可以处理一组设备。按照我的理解就是所有的设备都挂载到总线上,当加载驱动时,驱动就从总线上找到自己对应的设备。或者先把驱动加载上,来了一个设备就去总线找驱动。
-
这种基本关系的建立源于实际系统中各种总线,设备,驱动结构的抽象。
-
-
1.首先是总线,bus_type.
-
struct bus_type {
-
const char *name;//总线名称
-
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_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;
-
struct bus_type_private *p;
-
};
-
//bus_type的bus_type_private 成员
-
struct bus_type_private {
-
struct kset subsys;
-
struct kset *drivers_kset;
-
struct kset *devices_kset;
-
struct klist klist_devices;
-
struct klist klist_drivers;
-
struct blocking_notifier_head bus_notifier;
-
unsigned int drivers_autoprobe:1;
-
struct bus_type *bus;
-
};
-
(1)总线的删除
-
void bus_unregister(struct bus_type *bus);
-
(2)总线的match方法
-
int (*match)(struct device *dev, struct device_driver *drv);
-
//当一个新设备或者驱动被添加到这个总线时,该方法被调用,用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非0值。下面的测试程序采用匹配设备的dev->bus_id字符串和驱动的drv->name字符串是否相同来判断驱动是否能处理该设备。
-
(3)总线uevent方法
-
int (*uevent)(structdevice *dev, char **envp, int num_envp)//在为用户产生热插拔事件之前,这个方法允许总线添加环境变量。
-
(4)总线属性由结构bus_attribute描述:
-
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);
-
};
-
BUS_ATTR(name,mode, show, store)//在编译时创建和初始化bus_attribute结构,它将bus_attr_作为给定前缀来创建总线的真正名称。
-
如:static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);//将创建一个bus_attr_version结构体对象。
-
(5)创建\删除属性文件
-
int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
-
void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr)
-
(6)可以看出该结构体中包含了有device和dirver的kset对象。
-
总线的注册:int bus_register(structbus_type *bus);如果成功,新的总线将被添加到系统,在/sys/bus目录下可以看到。
-
int bus_register(struct bus_type *bus)
-
{
-
int retval;
-
struct bus_type_private *priv;
-
priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //分配空间
-
if (!priv)
-
return -ENOMEM;
-
priv->bus = bus;
-
bus->p = priv;//建立bus_type和bus_type_private的关系
-
-
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
-
//设置总线子系统kobject的名称
-
retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);//给总线的kset结构里的kobject结构设置name,在/sys/bus目录下出现时就是这个bus名
-
if (retval)
-
goto out;
-
-
priv->subsys.kobj.kset = bus_kset;//设置总线子系统kobject的所属集合,其实对应sys/bus/ 目录
-
priv->subsys.kobj.ktype = &bus_ktype;//kobj_type类型变量,和sysfs有关
-
priv->drivers_autoprobe = 1; //这个变量如果置位,则会执行一个函数,在驱动注册会看到它的运用
-
-
//注册kset,就是建立/sys/bus/bus->name的目录
-
retval = kset_register(&priv->subsys);
-
if (retval)
-
goto out;
-
-
//创建bus的属性文件
-
retval = bus_create_file(bus, &bus_attr_uevent);//调用sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
-
if (retval)
-
goto bus_uevent_fail;
-
-
//在/sys/bus/bus->name目录下创建devices目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录
-
priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);
-
if (!priv->devices_kset) {
-
retval = -ENOMEM;
-
goto bus_devices_fail;
-
}
-
-
//在/sys/bus/bus->name目录下创建drivers目录,父目录就是priv->subsys.kobj,即/sys/bus/bus->name的目录
-
priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);
-
if (!priv->drivers_kset) {
-
retval = -ENOMEM;
-
goto bus_drivers_fail;
-
}
-
-
// //初始化总线设备\总线驱动链表
-
klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
-
klist_init(&priv->klist_drivers, NULL, NULL);
-
-
retval = add_probe_files(bus);//添加探测属性retval = bus_create_file(bus, &bus_attr_drivers_probe); retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
-
if (retval)
-
goto bus_probe_files_fail;
-
-
retval = bus_add_attrs(bus);// 添加其他属性,bus_create_file(bus, &bus->bus_attrs[i]);
-
if (retval)
-
goto bus_attrs_fail;
-
-
pr_debug("bus: '%s': registered\n", 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:
-
return retval;
-
}
-
-
2.下面是设备device的定义:
-
struct device {
-
struct klist klist_children;
-
struct klist_nodeknode_parent;/* node in sibling list */
-
struct klist_nodeknode_driver;
-
struct klist_nodeknode_bus;
-
struct device *parent;//父设备,一般一个bus也对应一个设备。
-
struct kobject kobj; //代表自身
-
char bus_id[BUS_ID_SIZE];/* position on parent bus */
-
unsigned uevent_suppress:1;
-
const char *init_name; /*设备初始名 */
-
struct device_type*type;
-
struct semaphoresem;/* semaphore to synchronize calls to its driver. */
-
struct bus_type*bus;/* 所属的总线 */
-
struct device_driver *driver; /* 匹配的驱动*/
-
void *driver_data;/* data private to the driver */
-
void *platform_data;/* 由驱动定义并使用 */
-
struct dev_pm_infopower;
-
u64 *dma_mask;/* dma mask (if dma'able device) */
-
u64 coherent_dma_mask;
-
struct device_dma_parameters *dma_parms;
-
struct list_headdma_pools;/* dma pools (if dma'ble) */
-
struct dma_coherent_mem*dma_mem; /* internal for coherent mem override */
-
struct dev_archdataarchdata; /* arch specific additions */
-
dev_t devt;/* dev_t, creates the sysfs "dev" */
-
spinlock_t devres_lock;
-
struct list_headdevres_head;
-
struct klist_nodeknode_class;
-
struct class *class;
-
struct attribute_group**groups;/* optional groups */
-
void (*release)(struct device *dev);
-
};
-
-
//可以看出device结构体中也包含了一个kobject对象
-
(1)注册设备
-
int device_register(struct device *dev);
-
(2)注销设备
-
viod device_unregister(struct device *dev)
-
(3)设备属性由struct device_attribute描述
-
structdevice_attribute {
-
struct attribute attr;
-
ssize_t (*show)(struct device *dev,struct device_attribute *attr,char *buf);
-
ssize_t (*store)(struct device *dev,struct device_attribute *attr,const char *buf, size_t count);
-
};
-
(4)创建属性文件
-
int device_create_file(struct device *dev, struct device_attibute *entry)
-
(5)删除属性文件
-
void device_remove_file(struct device *dev, struct device_attibute *entry)
-
(6)device_register代码
-
int device_register(struct device *dev)
-
{
-
device_initialize(dev);//初始化设备各个字段
-
return device_add(dev);
-
}
-
-
void device_initialize(struct device *dev)
-
{
-
kobj_set_kset_s(dev, devices_subsys); //所有的dev属于devices_subsys这个集合
-
kobject_init(&dev->kobj); //初始kobj
-
klist_init(&dev->klist_children, klist_children_get,klist_children_put);//初始化子设备链表
-
INIT_LIST_HEAD(&dev->dma_pools);
-
INIT_LIST_HEAD(&dev->node);
-
init_MUTEX(&dev->sem);
-
device_init_wakeup(dev, 0);
-
}
-
int device_add(struct device *dev)
-
{
-
struct device *parent = NULL;
-
struct kobject *kobj;
-
struct class_interface *class_intf;
-
int error = -EINVAL;
-
-
dev = get_device(dev);//增加使用计数
-
if (!dev)
-
goto done;
-
-
if (!dev->p) {
-
/*int device_private_init(struct device *dev)
-
{
-
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
-
if (!dev->p)
-
return -ENOMEM;
-
dev->p->device = dev;//指向设备自己
-
klist_init(&dev->p->klist_children, klist_children_get,klist_children_put);//初始化设备私有成员的子设备链表,还有两个函数,关于增加和减少子设备引用计数的
-
return 0;
-
}
-
*/
-
error = device_private_init(dev);
-
if (error)
-
goto done;
-
}
-
-
if (dev->init_name) {//设备初始名存在
-
/*
-
int dev_set_name(struct device *dev, const char *fmt, ...)
-
{
-
va_list vargs;
-
int err;
-
-
va_start(vargs, fmt);
-
err = kobject_set_name_vargs(&dev->kobj, fmt, vargs);
-
va_end(vargs);
-
return err;
-
}
-
*/
-
dev_set_name(dev, "%s", dev->init_name);//赋值给设备本身的kobject结构的name
-
dev->init_name = NULL;
-
}
-
-
/*检查设备名是否存在,否则使用dev->bus->dev_name, dev->id生成设备本身的kobject结构的name*/
-
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
-
dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
-
-
if (!dev_name(dev)) {//再次检查name
-
error = -EINVAL;
-
goto name_error;
-
}
-
-
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
-
-
parent = get_device(dev->parent);//增加父设备计数,并返回父设备结构
-
kobj = get_device_parent(dev, parent);//找到父设备对应的kobject结构
-
if (kobj)
-
dev->kobj.parent = kobj;//将本设备的kobj的parent字段指向父设备的kobject结构
-
-
/* use parent numa_node */
-
if (parent)
-
set_dev_node(dev, dev_to_node(parent));// dev->numa_node = node;
-
-
//将Kobject对象注册到linux系统,即在dev->kobj.parent的目录下创建前边设置过的name的本设备的目录
-
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
-
if (error)
-
goto Error;
-
-
/* notify platform of device entry */
-
if (platform_notify)
-
platform_notify(dev);
-
-
//为sysfs文件系统创建设备的属性文件
-
error = device_create_file(dev, &uevent_attr);
-
if (error)
-
goto attrError;
-
-
if (MAJOR(dev->devt)) {//如果存在设备号则添加dev_t属性,这样udev就能读取设备号属性从而在/dev/目录下创建设备节点,这样kobj和cdev也关联了
-
error = device_create_file(dev, &devt_attr);//创建属性文件static struct device_attribute devt_attr =__ATTR(dev, S_IRUGO, show_dev, NULL);
-
if (error)
-
goto ueventattrError;
-
-
//创建一些符号链接
-
error = device_create_sys_dev_entry(dev);
-
if (error)
-
goto devtattrError;
-
-
devtmpfs_create_node(dev);//在/dev下动态创建设备节点
-
}
-
-
//建立类的sysfs符号连接
-
error = device_add_class_symlinks(dev);
-
if (error)
-
goto SymlinkError;
-
error = device_add_attrs(dev);//调用device_create_file(dev, &bus->dev_attrs[i])为sysfs文件系统创建属性文件
-
if (error)
-
goto AttrsError;
-
error = bus_add_device(dev);//创建bus的一些符号链接,将设备添加进总线中
-
if (error)
-
goto BusError;
-
error = dpm_sysfs_add(dev);//电源管理
-
if (error)
-
goto DPMError;
-
device_pm_add(dev);//电源管理
-
-
if (dev->bus)//调用注册bus通知链上的所有函数
-
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_ADD_DEVICE, dev);
-
-
//主要是向用户空间发送消息,实现热插拔
-
kobject_uevent(&dev->kobj, KOBJ_ADD);
-
bus_probe_device(dev); //现在该为设备在总线上寻找合适的驱动了
-
if (parent)//如果父设备存在
-
klist_add_tail(&dev->p->knode_parent,&parent->p->klist_children);//将子设备添加到父设备的链表中
-
-
if (dev->class) {
-
mutex_lock(&dev->class->p->mutex);
-
klist_add_tail(&dev->knode_class,&dev->class->p->klist_devices); /* tie the class to the device */
-
-
/* notify any interfaces that the device is here */
-
list_for_each_entry(class_intf,&dev->class->p->interfaces, node)
-
if (class_intf->add_dev)
-
class_intf->add_dev(dev, class_intf);
-
mutex_unlock(&dev->class->p->mutex);
-
}
-
done:
-
put_device(dev);
-
return error;
-
.......//出错处理
-
}
-
-
int bus_add_device(struct device *dev)
-
{
-
struct bus_type *bus = bus_get(dev->bus);
-
int error = 0;
-
-
if (bus) {
-
pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev));
-
error = device_add_attrs(bus, dev);//创建属性文件
-
if (error)
-
goto out_put;
-
error = sysfs_create_link(&bus->p->devices_kset->kobj,&dev->kobj, dev_name(dev));//创建设备所在bus目录下的设备链接
-
if (error)
-
goto out_id;
-
error = sysfs_create_link(&dev->kobj,&dev->bus->p->subsys.kobj, "subsystem");//创建链接
-
if (error)
-
goto out_subsys;
-
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);//将设备添加到所在bus总线下的链表中,将设备添加进总线的设备链表
-
}
-
return 0;
-
-
out_subsys:
-
sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev));
-
out_id:
-
device_remove_attrs(bus, dev);
-
out_put:
-
bus_put(dev->bus);
-
return error;
-
}
-
-
void bus_probe_device(struct device *dev)
-
{
-
struct bus_type *bus = dev->bus;//找到设备所在的总线
-
int ret;
-
-
if (bus && bus->p->drivers_autoprobe) {//drivers_autoprobe标志设为1,表明要自动匹配驱动
-
ret = device_attach(dev); //为设备寻找驱动
-
WARN_ON(ret < 0);
-
}
-
}
-
-
int device_attach(struct device *dev)
-
{
-
int ret = 0;
-
-
device_lock(dev);//锁住设备
-
if (dev->driver) {//如果设备有驱动
-
ret = device_bind_driver(dev);//那么将设备和驱动绑定
-
if (ret == 0)
-
ret = 1;
-
else {
-
dev->driver = NULL;
-
ret = 0;
-
}
-
} else {//如果设备没有驱动
-
pm_runtime_get_noresume(dev);
-
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //在总线上寻找驱动与该设备进行匹配
-
pm_runtime_put_sync(dev);
-
}
-
device_unlock(dev);
-
return ret;
-
}
-
-
int device_bind_driver(struct device *dev)
-
{
-
int ret;
-
-
ret = driver_sysfs_add(dev);//主要是添加driver和dev之间的连接文件
-
if (!ret)
-
driver_bound(dev);//驱动绑定设备
-
return ret;
-
}
-
-
static int driver_sysfs_add(struct device *dev)
-
{
-
int ret;
-
//1:在驱动目录下建立一个到设备的同名链接
-
//2:在设备目录下建立一个名为driver。到驱动的链接
-
ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,kobject_name(&dev->kobj)); //在driver目录下添加以dev->kobj名字的连接文件,连接到device
-
if (ret == 0) {
-
ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,"driver"); //同样在device目录下添加‘driver’为名字的连接文件连接到drvier
-
if (ret)
-
sysfs_remove_link(&dev->driver->p->kobj,kobject_name(&dev->kobj));
-
}
-
return ret;
-
}
-
-
static void driver_bound(struct device *dev)
-
{
-
if (klist_node_attached(&dev->p->knode_driver)) {
-
printk(KERN_WARNING "%s: device %s already bound\n",__func__, kobject_name(&dev->kobj));
-
return;
-
}
-
-
pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),__func__, dev->driver->name);
-
-
//实现将驱动程序和设备联系起来。
-
klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
-
-
if (dev->bus)//调用注册bus通知链上的所有函数
-
blocking_notifier_call_chain(&dev->bus->p->bus_notifier,BUS_NOTIFY_BOUND_DRIVER, dev);
-
}
-
-
int bus_for_each_drv(struct bus_type *bus, struct device_driver *start,void *data, int (*fn)(struct device_driver *, void *))
-
{
-
struct klist_iter i;
-
struct device_driver *drv;
-
int error = 0;
-
-
if (!bus)
-
return -EINVAL;
-
-
klist_iter_init_node(&bus->p->klist_drivers, &i,start ? &start->p->knode_bus : NULL); //初始化i结构体
-
while ((drv = next_driver(&i)) && !error)//遍历总线上的驱动
-
error = fn(drv, data);//将驱动和设备进行匹配,这里的fn=__device_attach
-
klist_iter_exit(&i);
-
return error;
-
}
-
-
-
static int __device_attach(struct device_driver *drv, void *data)
-
{
-
struct device *dev = data;
-
-
if (!driver_match_device(drv, dev))//现用总线上的match匹配函数进行低级匹配
-
return 0;
-
-
return driver_probe_device(drv, dev); //再来高级匹配
-
}
-
-
-
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
-
{
-
return drv->bus->match ? drv->bus->match(dev, drv) : 1;//看到没,这里要调用总线上定义的match函数,实际就是比较设备名和驱动名是否一样
-
}
-
-
int driver_probe_device(struct device_driver *drv, struct device *dev)
-
{
-
int ret = 0;
-
-
if (!device_is_registered(dev)) //设备是否注册,返回 return dev->kobj.state_in_sysfs
-
return -ENODEV;
-
-
pr_debug("bus: '%s': %s: matched device %s with driver %s/n",drv->bus->name, __func__, dev_name(dev), drv->name);
-
-
pm_runtime_get_noresume(dev);
-
pm_runtime_barrier(dev);
-
ret = really_probe(dev, drv);//调用真正的匹配
-
pm_runtime_put_sync(dev);
-
-
return ret;
-
}
-
-
static int really_probe(struct device *dev, struct device_driver *drv)
-
{
-
int ret = 0;
-
-
atomic_inc(&probe_count);
-
pr_debug("bus: '%s': %s: probing driver %s with device %s/n",drv->bus->name, __func__, drv->name, dev_name(dev));
-
WARN_ON(!list_empty(&dev->devres_head));
-
-
dev->driver = drv;
-
if (driver_sysfs_add(dev)) {//主要是添加driver和dev之间的连接文件,见上
-
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",__func__, dev_name(dev));
-
goto probe_failed;
-
}
-
-
if (dev->bus->probe) {//现用总线上定义的probe函数尝试一下
-
ret = dev->bus->probe(dev);
-
if (ret)
-
goto probe_failed;
-
} else if (drv->probe) {//如果不行,在用驱动上的probe尝试
-
ret = drv->probe(dev);
-
if (ret)
-
goto probe_failed;
-
}
-
-
driver_bound(dev);//驱动绑定设备
-
ret = 1;
-
pr_debug("bus: '%s': %s: bound device %s to driver %s/n",drv->bus->name, __func__, dev_name(dev), drv->name);
-
goto done;
-
-
probe_failed:
-
devres_release_all(dev);
-
driver_sysfs_remove(dev);
-
dev->driver = NULL;
-
-
if (ret != -ENODEV && ret != -ENXIO) {/* driver matched but the probe failed */
-
printk(KERN_WARNING"%s: probe of %s failed with error %d/n",drv->name, dev_name(dev), ret);
-
}
-
-
ret = 0;
-
done:
-
atomic_dec(&probe_count);
-
wake_up(&probe_waitqueue);
-
return ret;
-
}
-
-
3.下面是设备驱动定义:
-
struct device_driver {
-
const char *name;//驱动名称
-
struct bus_type*bus; //所在总线
-
struct module *owner;
-
const char *mod_name;/* used for built-in modules */
-
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 attribute_group **groups;
-
struct dev_pm_ops *pm;
-
struct driver_private *p; //
-
};
-
-
struct driver_private {
-
struct kobject kobj;//代表自身
-
struct klist klist_devices;//设备列表
-
struct klist_node knode_bus;
-
struct module_kobject *mkobj;
-
struct device_driver *driver;
-
};
-
-
(1)当总线的match返回非0值,也就是总线找到与驱动相匹配的设备时,驱动的probe的函数将被调用。
-
(2)当设备从系统总删除是remove被调用。
-
(3)当系统关机的时候shutdown被调用。
-
(4)创建属性文件
-
int dirver_create_file(struct device_driver *drv, struct driver_attribute *attr);
-
(5)删除属性文件
-
void driver_remove_file struct device_driver *drv, struct driver_attribute *attr);
-
(6)驱动的属性使用structdriver_attribute来描述
-
structdriver_attribute{
-
structattribue attr;
-
ssize_t(*show)(struct device_driver *drv, const char *buf);
-
ssize_t(*store)(struct device_driver *drv, const char *buf, size_t count);
-
}
-
(7)卸载总线上注销驱动
-
int driver_register(structdevice_driver *drv)
-
(8)在总线上注册驱动
-
void driver_unregister(struct device_driver *drv)
-
(9)代码分析
-
int driver_register(struct device_driver *drv)
-
{
-
int ret;
-
struct device_driver *other;
-
-
BUG_ON(!drv->bus->p); //判断bus->p是否为空
-
-
if ((drv->bus->probe && drv->probe) || //判断驱动跟驱动的总线是否有冲突的函数注册,给出警告信息
-
(drv->bus->remove && drv->remove) ||
-
(drv->bus->shutdown && drv->shutdown))
-
printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);
-
-
other = driver_find(drv->name, drv->bus); //在注册在bus上的driver寻找是否有跟要注册的driver相同,有则表明驱动已被注册过
-
if (other) {
-
put_driver(other);
-
printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);
-
return -EBUSY;
-
}
-
-
ret = bus_add_driver(drv); //经过上面的验证后,将驱动添加注册到bus上
-
if (ret)
-
return ret;
-
ret = driver_add_groups(drv, drv->groups); //如果grop不为空的话,将在驱动文件夹下创建以group名字的子文件夹,然后在子文件夹下添加group的属性文件
-
if (ret)
-
bus_remove_driver(drv);
-
return ret;
-
}
-
-
int bus_add_driver(struct device_driver *drv)
-
{
-
struct bus_type *bus;
-
struct driver_private *priv;
-
int error = 0;
-
-
bus = bus_get(drv->bus);//找到该drv所属的bus,其实就是增加该bus->p->subsys->kobject->kref的引用计数
-
if (!bus)
-
return -EINVAL;
-
-
pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
-
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);//分配driver_private结构
-
if (!priv) {
-
error = -ENOMEM;
-
goto out_put_bus;
-
}
-
klist_init(&priv->klist_devices, NULL, NULL);//初始化priv->klist_devices
-
priv->driver = drv; //将该drv赋值给priv->driver
-
drv->p = priv; //而drv的drv->p又等于priv
-
priv->kobj.kset = bus->p->drivers_kset; //指向bus的drvier容器
-
//在sysfs文件系统下在总线所在的drivers_kset目录下添加该驱动的目录
-
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,"%s", drv->name); //驱动的kobject初始化和添加dir到sysfs中
-
if (error)
-
goto out_unregister;
-
-
if (drv->bus->p->drivers_autoprobe) { //这个变量默认是为1的
-
error = driver_attach(drv); //匹配相应的设备
-
if (error)
-
goto out_unregister;
-
}
-
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //将priv->knode_bus添加到bus->p->klist_drivers,即添加到总线上
-
module_add_driver(drv->owner, drv); //添加drv的module
-
-
error = driver_create_file(drv, &driver_attr_uevent); //在sysfs的目录下创建文件uevent属性文件
-
if (error) {
-
printk(KERN_ERR "%s: uevent attr (%s) failed\n",__func__, drv->name);
-
}
-
error = driver_add_attrs(bus, drv);//给driver添加bus上的所有属性
-
if (error) {
-
printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",__func__, drv->name);
-
}
-
error = add_bind_files(drv); //添加绑定文件,driver_attr_bind 和 driver_attr_unbind
-
if (error) {
-
printk(KERN_ERR "%s: add_bind_files(%s) failed\n", __func__, drv->name);
-
}
-
-
kobject_uevent(&priv->kobj, KOBJ_ADD); //产生一个KOBJ_ADD uevent
-
return 0;
-
out_unregister:
-
kfree(drv->p);
-
drv->p = NULL;
-
kobject_put(&priv->kobj);
-
out_put_bus:
-
bus_put(bus);
-
return error;
-
}
-
-
int driver_attach(struct device_driver *drv)
-
{
-
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
-
}
-
-
//该函数将调用bus_for_each_dev()。
-
int bus_for_each_dev(struct bus_type *bus, struct device *start,void *data, int (*fn)(struct device *, void *))
-
{
-
struct klist_iter i;
-
struct device *dev;
-
int error = 0;
-
-
if (!bus)
-
return -EINVAL;
-
-
klist_iter_init_node(&bus->p->klist_devices, &i,(start ? &start->p->knode_bus : NULL)); //将bus中的已注册的device列表放到迭代器中,方便索引
-
while ((dev = next_device(&i)) && !error) //将驱动逐个地与列表中每一个的device匹配,可能一个驱动匹配好几个设备
-
error = fn(dev, data); //这个fn就是上面传下来的__driver_attach
-
klist_iter_exit(&i);
-
return error;
-
}
-
-
static int __driver_attach(struct device *dev, void *data)
-
{
-
struct device_driver *drv = data;
-
if (!driver_match_device(drv, dev)) //跟名字的意思一样,driver跟device尝试匹配
-
return 0;
-
-
if (dev->parent) /* Needed for USB */
-
down(&dev->parent->sem);
-
down(&dev->sem);
-
if (!dev->driver)
-
driver_probe_device(drv, dev);//再来高级匹配
-
up(&dev->sem);
-
if (dev->parent)
-
up(&dev->parent->sem);
-
-
return 0;
-
}
-
-
static inline int driver_match_device(struct device_driver *drv,struct device *dev)
-
{
-
return drv->bus->match ? drv->bus->match(dev, drv) : 1;//调用总线的match函数
-
}
-
-
int driver_probe_device(struct device_driver *drv, struct device *dev)
-
{
-
int ret = 0;
-
-
if (!device_is_registered(dev)) //首先判断这个device是否已经注册
-
return -ENODEV;
-
-
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);
-
-
ret = really_probe(dev, drv); //转而调用really_probe(),同以上的device_register()里调用的
-
-
return ret;
-
}
-
-
void module_add_driver(struct module *mod, struct device_driver *drv)
-
{
-
char *driver_name;
-
int no_warn;
-
struct module_kobject *mk = NULL;
-
-
if (!drv)
-
return;
-
-
if (mod)//一般情况下为THIS_MODULE
-
mk = &mod->mkobj;
-
else if (drv->mod_name) {//如果没模块,则检查驱动的模块名
-
struct kobject *mkobj;
-
mkobj = kset_find_obj(module_kset, drv->mod_name); //根据驱动模块的名字去module_kset集合中找
-
if (mkobj) {
-
mk = container_of(mkobj, struct module_kobject, kobj); //用container_of方法通过kobj转换成module_kobject
-
drv->p->mkobj = mk; //赋值给驱动的mkobj
-
kobject_put(mkobj);
-
}
-
}
-
-
if (!mk) //mk如果为null则返回
-
return;
-
-
no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module"); //在驱动文件夹下创建名为‘module’的链接文件,链接到module文件夹
-
driver_name = make_driver_name(drv); //生成driver_name,给module用
-
if (driver_name) {
-
module_create_drivers_dir(mk); //在具体的module文件夹下创建driver目录
-
no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,make_driver_name()); //在上面创建的driver目录下,生成一个名为driver_name指定的链接文件,链接到驱动的文件夹
-
kfree(driver_name);
-
}
-
}
-
总体来说,驱动的注册比较复杂,但是我们可以简单概况一下。
-
1、在总线上找找该驱动有没有被注册过
-
2、若没有注册过,则将驱动加入到总线驱动集合中
-
3、在总线上找能匹配驱动的设备
-
1、将总线上每个设备进行匹配
-
2、首先用总线的match 函数进行低级匹配
-
3、然后在用总线的probe函数进行高级匹配,若失败,则用驱动上的probe寒酸进行高级匹配
-
4、如果匹配成功,则将设备绑定到驱动链表中
-
4、如果匹配成功,则将驱动加入到总线的驱动链表中
-
-
4、结束语
-
系统初始化时,会扫描连接那些设备,并为扫描到的设备建立一个struct device的变量,接下来就是驱动,每次扫描有一个驱动程序,就要为其分配一个struct device_driver结构变量,并把这些变量加入相应的链表中,device插入devices、driver插入drivers中去,这样总线伤的两条链表变这样诞生了。在以前的系统中都是先有设备后又驱动的,因为设备都是先插好了再商店开机的。这样devices链表会先被创建,而后就是drivers链表,然后驱动程序就开始初始化,开始注册其struct devicr_driver结构,然后他就去总线的devices链表中去寻找(遍历)还没有绑定driver的设备,即struct device中的struct device_driver指针乃为空的设备。然后去观察该设备的特征,若匹配就会调用device_bind_driver的函数结合在一起,换句话说,把struct device中的struct devicr_drive driver指向这个driver,而struct device_driver drivers加入他的那张struct klist *klist_devices链表中来,这样 bus、device、driver就建立起关系并联系起来了。
三、测试模块
1.BUS
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
-
MODULE_AUTHOR("David Xie");
-
MODULE_LICENSE("Dual BSD/GPL");
-
-
static char *Version = "$Revision: 1.9 {1}quot;;
-
-
static int my_match(struct device *dev, struct device_driver *driver)
-
{
-
return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
-
}
-
-
static void my_bus_release(struct device *dev)
-
{
-
printk(KERN_DEBUG "my bus release\n");
-
}
-
-
struct device my_bus = {
-
.bus_id = "my_bus0",
-
.release = my_bus_release
-
};
-
-
-
struct bus_type my_bus_type = {
-
.name = "my_bus",
-
.match = my_match,
-
};
-
-
EXPORT_SYMBOL(my_bus);
-
EXPORT_SYMBOL(my_bus_type);
-
-
-
/*
-
* Export a simple attribute.
-
*/
-
static ssize_t show_bus_version(struct bus_type *bus, char *buf)
-
{
-
return snprintf(buf, PAGE_SIZE, "%s\n", Version);
-
}
-
-
static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
-
-
-
static int __init my_bus_init(void)
-
{
-
int ret;
-
-
/*注册总线*/
-
ret = bus_register(&my_bus_type);
-
if (ret)
-
return ret;
-
-
/*创建属性文件*/
-
if (bus_create_file(&my_bus_type, &bus_attr_version))
-
printk(KERN_NOTICE "Fail to create version attribute!\n");
-
-
/*注册总线设备*/
-
ret = device_register(&my_bus);
-
if (ret)
-
printk(KERN_NOTICE "Fail to register device:my_bus!\n");
-
-
return ret;
-
}
-
-
static void my_bus_exit(void)
-
{
-
device_unregister(&my_bus);
-
bus_unregister(&my_bus_type);
-
}
-
-
module_init(my_bus_init);
-
module_exit(my_bus_exit);
创建一条名为my_bus_type的总线和一个名为my_bus的总线设备,注意总线也是一个设备,也需要注册。
测试结果:
2.DEVICE
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
-
MODULE_AUTHOR("David Xie");
-
MODULE_LICENSE("Dual BSD/GPL");
-
-
extern struct device my_bus;
-
extern struct bus_type my_bus_type;
-
-
/* Why need this ?*/
-
static void my_dev_release(struct device *dev)
-
{
-
-
}
-
-
struct device my_dev = {
-
.bus = &my_bus_type,
-
.parent = &my_bus,
-
.release = my_dev_release,
-
};
-
-
/*
-
* Export a simple attribute.
-
*/
-
static ssize_t mydev_show(struct device *dev, char *buf)
-
{
-
return sprintf(buf, "%s\n", "This is my device!");
-
}
-
-
static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
-
-
static int __init my_device_init(void)
-
{
-
int ret = 0;
-
-
/* 初始化设备 */
-
strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
-
-
/*注册设备*/
-
device_register(&my_dev);
-
-
/*创建属性文件*/
-
device_create_file(&my_dev, &dev_attr_dev);
-
-
return ret;
-
-
}
-
-
static void my_device_exit(void)
-
{
-
device_unregister(&my_dev);
-
}
-
-
module_init(my_device_init);
-
module_exit(my_device_exit);
注册一个bus_id即名字为my_dev的设备,该设备的bus成员指向上一步创建的my_bus_type总线,parent成员指向上一步创建的my_bus总线设备。
测试结果:
3.DRIVER
-
#include <linux/device.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/init.h>
-
#include <linux/string.h>
-
-
MODULE_AUTHOR("David Xie");
-
MODULE_LICENSE("Dual BSD/GPL");
-
-
extern struct bus_type my_bus_type;
-
-
static int my_probe(struct device *dev)
-
{
-
printk("Driver found device which my driver can handle!\n");
-
return 0;
-
}
-
-
static int my_remove(struct device *dev)
-
{
-
printk("Driver found device unpluged!\n");
-
return 0;
-
}
-
-
struct device_driver my_driver = {
-
.name = "my_dev",
-
.bus = &my_bus_type,
-
.probe = my_probe,
-
.remove = my_remove,
-
};
-
-
/*
-
* Export a simple attribute.
-
*/
-
static ssize_t mydriver_show(struct device_driver *driver, char *buf)
-
{
-
return sprintf(buf, "%s\n", "This is my driver!");
-
}
-
-
static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);
-
-
static int __init my_driver_init(void)
-
{
-
int ret = 0;
-
-
/*注册驱动*/
-
driver_register(&my_driver);
-
-
/*创建属性文件*/
-
driver_create_file(&my_driver, &driver_attr_drv);
-
-
return ret;
-
-
}
-
-
static void my_driver_exit(void)
-
{
-
driver_unregister(&my_driver);
-
}
-
-
module_init(my_driver_init);
-
module_exit(my_driver_exit);
创建一个名为“bus_dev”的驱动,并将bus成员指向第一步创建的my_bus_type总线
阅读(2850) | 评论(0) | 转发(4) |