免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 908 | 回复: 0
打印 上一主题 下一主题

linux 驱动模型相关初始化函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-05-11 19:23 |只看该作者 |倒序浏览

driver study
  
一、内核初始化
     内核中驱动相关的调用顺序如下:
       start_kernel
rest_init()
       kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND)
              static int init(void * unused)
                     do_basic_setup()
下面分析一下函数:
do_basic_setup()
static void __init do_basic_setup(void)
{
       init_workqueues(); //这个是初始化hotplug用到的工作队列 keventd_wq
       usermodehelper_init();//初始化信号相关的工作队列khelper_wq
       driver_init();//初始化驱动程序子系统
#ifdef CONFIG_SYSCTL
       sysctl_init();
#endif
       sock_init();//网络相关的初始化,如果没有用到网络,可以注释掉
       do_initcalls();//初始化驱动的各个模块
}
driver_init()
void __init driver_init(void)
{//这个函数运行完后,各个子系统都初始化了,而且platform设备和platform_bus已经初始化。
       /* These are the core pieces */
       devices_init();//设备子系统初始化
       buses_init();//总线子系统初始化
       classes_init();//类和类设备子系统初始化
       firmware_init();//固件子系统初始化
       /* These are also core pieces, but must come after thecore core pieces.*/
       platform_bus_init();//平台设备和平台总线初始化
       system_bus_init();//系统总线初始化,它的父设备是设备子系统
       cpu_dev_init();//cpu的设备初始化
       attribute_container_init();//初始化attribute_container_list,
}
在这个函数中主要是用到subsystem_register(struct subsystem *s)函数,下面分析这个函数:
subsystem_register()
int subsystem_register(struct subsystem * s)
{
       int error;
       subsystem_init(s);//初始化要注册的子系统,后面分析
       pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
       if (!(error = kset_add(&s->kset))) {
              if (!s->kset.subsys)
                     s->kset.subsys = s;
       }
       return error;
}
下面分析subsystem_init:
subsystem_init()
void subsystem_init(struct subsystem * s)
{//增加子系统中kset的引用计数,同时也初始化,kset中kboj指向的kset的引用计数。
       init_rwsem(&s->rwsem);//初始化读写信号量,包括自旋锁和等待队列头的初始化,见后面
       kset_init(&s->kset);//kset的初始化,见后面
}
init_rwsem()
void fastcall init_rwsem(struct rw_semaphore *sem)
{
       sem->activity = 0;
       spin_lock_init(&sem->wait_lock);//自旋锁的初始化
       INIT_LIST_HEAD(&sem->wait_list);//等待队列头的初始化
#if RWSEM_DEBUG
       sem->debug = 0;
#endif
}
kset_init()
void kset_init(struct kset * k)
{//增加嵌入在kset中kobj的引用计数,和kobj指向的kset的引用计数,并初始化队列头和kset的自旋锁
       kobject_init(&k->kobj);//嵌套在kset中kobject的初始化,见后面
       INIT_LIST_HEAD(&k->list);//队列头的初始化
       spin_lock_init(&k->list_lock);//kset自旋锁的初始化
}
kobject_init()
void kobject_init(struct kobject * kobj)
{//增加传入kobj的引用计数,同时也增加kobj指向的kset的引用计数,并设置队列头
       kref_init(&kobj->kref);//设置原子变量kref->refcount为1,见后面
       INIT_LIST_HEAD(&kobj->entry);//设置队列头
       kobj->kset = kset_get(kobj->kset);//增加kobj指向的kset中kboj的引用计数,见后面
}
kref_init()
void kref_init(struct kref *kref)
{//设置kref->refcount的引用计数为1
       atomic_set(&kref->refcount,1);//设置原子变量为1
}
kset_get()
static inline struct kset * kset_get(struct kset * k)
{//增加嵌入在kset中kobj的引用计数,并返回传入的kset
       return k ? to_kset(kobject_get(&k->kobj)) : NULL;//增加kset中kobj的引用计数,并返回kset
}
kobject_get()
struct kobject * kobject_get(struct kobject * kobj)
{//增加kobj的引用计数,也就是kref->refcount+1,并返回传入的kobj
       if (kobj)
              kref_get(&kobj->kref);//原子变量kref加1,也就是增加引用计数
       return kobj;
}
to_kset()
static inline struct kset * to_kset(struct kobject * kobj)
{//如果参数不为空,就返回kobj所嵌入的kset
       return kobj ? container_of(kobj,struct kset,kobj) : NULL;
}
kset_add()
int kset_add(struct kset * k)
{//1、如果嵌入的kobj的父指针为空,而且kobj指向的kset也为空并且kset的subsystem不为空,那么,kobj的父指针指向所属subsys的kset中的kobj。
//2、然后把kobj增加的相应的kset中(如果有),创建相应的目录。
       if (!k->kobj.parent && !k->kobj.kset && k->subsys)//如果嵌入的kobj的父指针为空,而且kobj指向的kset也为空并且kset的subsystem不为空,那么,kobj的父指针指向所属subsys的kset中的kobj。
              k->kobj.parent = &k->subsys->kset.kobj;/
       return kobject_add(&k->kobj);
}
int kobject_add(struct kobject * kobj)
{//1、增加kobj和父节点的引用计数,并设置k_name
//2、如果指向kset,把自己加到kset的链表中,并设置父指针
//3、在sysfs中建立相应的目录
       int error = 0;
       struct kobject * parent;
       if (!(kobj = kobject_get(kobj)))//增加kobj的引用计数
              return -ENOENT;
       if (!kobj->k_name)//如果k_name为空,则k_name=kobj的name
              kobj->k_name = kobj->name;
       parent = kobject_get(kobj->parent);//增加父kobj的引用计数
       pr_debug("kobject %s: registering. parent: %s, set: %s\n",kobject_name(kobj), parent ? kobject_name(parent) : "", kobj->kset ? kobj->kset->kobj.name : "" );
       if (kobj->kset) {//如果kobj指向一个kset,
              spin_lock(&kobj->kset->list_lock);
              if (!parent)
                     parent = kobject_get(&kobj->kset->kobj);//那么kobj的父指针指向嵌入到kset中的kobj,并增加父kobj的计数,从这也可以看出,kobj->kset指向的应该是kobj的父kobj嵌入的kset。
              list_add_tail(&kobj->entry,&kobj->kset->list);//把kobj添加到父kobj嵌入的kset中。
              spin_unlock(&kobj->kset->list_lock);
       }
       kobj->parent = parent;//父指针指向kobj->kset->kobj
       error = create_dir(kobj);//这个留到分析文件系统的时候分析吧,哈哈
       if (error) {//如果出现错误,
              /* unlink does the kobject_put() for us */
              unlink(kobj);//从kobj->kset->list中删除kobj,并减小kobj的引用计数
              if (parent)//如果有父节点,减小父节点的引用计数
                     kobject_put(parent);
       }
       return error;
}
       下面分析do_initcalls:
do_initcalls()
static void __init do_initcalls(void)
{//主要是调用模块的初始化函数
       initcall_t *call;
       int count = preempt_count(); //
       for (call = __initcall_start; call 调用段中的函数,这些函数都是在编译的过程中安装的
              char *msg;
              if (initcall_debug) {//这个是调试信息
                     printk(KERN_DEBUG "Calling initcall 0x%p", *call);
                     print_fn_descriptor_symbol(": %s()", (unsigned long) *call);
                     printk("\n");
              }
              (*call)();//调用编译时通过宏安装的函数,那些宏在后面列出
              msg = NULL;
              if (preempt_count() != count) {
                     msg = "preemption imbalance";
                     preempt_count() = count;
              }
              if (irqs_disabled()) {
                     msg = "disabled interrupts";
                     local_irq_enable();
              }
              if (msg) {
                     printk(KERN_WARNING "error in initcall at 0x%p: "
                            "returned with %s\n", *call, msg);
              }
       }
       /* Make sure there is no pending stuff from the initcall sequence */
       flush_scheduled_work();

}

下面是驱动安装的宏,1234567是在段中的优先级,1最高,也就是最先被调用。但是当有多个宏是1时,先调用谁是随机的。其他同理。
#define __define_initcall(level,fn)  static initcall_t __initcall_##fn __attribute_used__ \
       __attribute__((__section__(".initcall" level ".init"))) = fn

#define core_initcall(fn)        __define_initcall("1",fn)
#define postcore_initcall(fn)         __define_initcall("2",fn)
#define arch_initcall(fn)        __define_initcall("3",fn)
#define subsys_initcall(fn)            __define_initcall("4",fn)
#define fs_initcall(fn)                   __define_initcall("5",fn)
#define device_initcall(fn)             __define_initcall("6",fn)
#define late_initcall(fn)          __define_initcall("7",fn)

#define __initcall(fn) device_initcall(fn)

#define __exitcall(fn)  static exitcall_t __exitcall_##fn __exit_call = fn
#define console_initcall(fn)  static initcall_t __initcall_##fn \
__attribute_used__ __attribute__((__section__(".con_initcall.init")))=fn
#define security_initcall(fn)  static initcall_t __initcall_##fn \
       __attribute_used__ __attribute__((__section__(".security_initcall.init"))) = fn   

#define module_init(x)   __initcall(x);// 6
#define module_exit(x)   __exitcall(x);

device_register()
int device_register(struct device *dev)
{
       device_initialize(dev);
       return device_add(dev);
}
device_initialize()
void device_initialize(struct device *dev)
{//1、设置dev的父设备,增加引用计数,设置klist_children、信号量
       // #define kobj_set_kset_s(obj,subsys)  (obj)->kobj.kset = &(subsys).kset
       kobj_set_kset_s(dev, devices_subsys);//设置要加入的设备的父节点为devices_subsys子系统
       kobject_init(&dev->kobj);//上面分析过,增加自身和指向的kset的引用计数,设置队列
       klist_init(&dev->klist_children, klist_children_get,klist_children_put);//设置klist
       INIT_LIST_HEAD(&dev->dma_pools);
       init_MUTEX(&dev->sem);
}

device_add()
int device_add(struct device *dev)
{//1、增加设备引用计数,如果有父设备,增加父设备引用计数
//2、设置name和k_name
//3、如果父设备存在,kobj指向父设备的kobj,然后调用热插拔
//4、匹配设备需要的驱动程序,然后加到父设备的孩子链表中
       struct device *parent = NULL;
       int error = -EINVAL;
       dev = get_device(dev);//增加嵌入到设备中的kobj的引用计数
       if (!dev || !strlen(dev->bus_id))//设备和设备的ID为0,就出错,ID在后面会用到
              goto Error;
       parent = get_device(dev->parent);//增加父设备的引用计数
       pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
       /* first, register with generic layer. */
       kobject_set_name(&dev->kobj, "%s", dev->bus_id);//申请空间,复制ID到申请的空间中,同时设置k_name
       if (parent)//如果父设备存在,kobj的父节点指向父设备的kobj
              dev->kobj.parent = &parent->kobj;
       if ((error = kobject_add(&dev->kobj)))//在kset中增加kobj
              goto Error;
       kobject_hotplug(&dev->kobj, KOBJ_ADD);//后面分析
       if ((error = device_pm_add(dev)))//没有仔细看
              goto PMError;
       if ((error = bus_add_device(dev)))//后面分析
              goto BusError;
       if (parent)//如果存在父设备,那么就把自己加到父设备的klist_children链表中去
              klist_add_tail(&dev->knode_parent, &parent->klist_children);
       /* notify platform of device entry */
       if (platform_notify)//不是很明白
              platform_notify(dev);
Done:
       put_device(dev);
       return error;
BusError:
       device_pm_remove(dev);
PMError:
       kobject_hotplug(&dev->kobj, KOBJ_REMOVE);
       kobject_del(&dev->kobj);
Error:
       if (parent)
              put_device(parent);
       goto Done;
}

bus_add_device()
int bus_add_device(struct device * dev)
{//1、增加总线的引用计数
//2、邦定驱动到设备,建立属性文件,和连接文件
       struct bus_type * bus = get_bus(dev->bus);//增加引用计数,并返回bus_type
       int error = 0;

       if (bus) {
              pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
              device_attach(dev);//邦定设备驱动程序到设备
              klist_add_tail(&dev->knode_bus, &bus->klist_devices);//把设备增加到bus的设备链表中
              error = device_add_attrs(bus, dev);//属性文件的建立
              if (!error) {
                     sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
                     sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
              }
       }
       return error;
}

device_attach()
int device_attach(struct device * dev)
{//1、遍历和绑定驱动程序到设备,
       int ret = 0;
       down(&dev->sem);
       if (dev->driver) {//如果设备的驱动链表不为空
              device_bind_driver(dev);
              ret = 1;
       } else//驱动的设备链表为空
              ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach); //遍历总线上所有的驱动,调用__device_attach
       up(&dev->sem);
       return ret;
}

device_bind_driver()
void device_bind_driver(struct device * dev)
{//1、把设备和驱动联系起来,通过设备的knode和驱动的klist,
//2、建立相关文件夹
       if (klist_node_attached(&dev->knode_driver))//如果驱动的链表为空,就没有办法邦定驱动程序了,所以退出
              return;
       pr_debug("bound device '%s' to driver '%s'\n",dev->bus_id, dev->driver->name);
       klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);//把设备的knode加到驱动的klist

       sysfs_create_link(&dev->driver->kobj, &dev->kobj,kobject_name(&dev->kobj));//文件系统的时候分析
       sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
}

bus_for_each_drv()
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->klist_drivers, &i,start ? &start->knode_bus : NULL);//初始化迭代链表
       while ((drv = next_driver(&i)) && !error)//函数返回值为0并且drv不为空,对每一个驱动,调用__device_attach,见下面
              error = fn(drv, data);
       klist_iter_exit(&i);//删除迭代链表
       return error;
}
__device_attach()
static int __device_attach(struct device_driver * drv, void * data)//传进来的参数应该是bus上的driver和要加入的device
{//1、总线级匹配,并调用驱动程序的probe函数
       struct device * dev = data;//传进来的device结构
       return driver_probe_device(drv, dev);//下面分析
}

driver_probe_device()
int driver_probe_device(struct device_driver * drv, struct device * dev)
{//总线匹配后,调用驱动程序的probe,最终完成设备和驱动的绑定
       int ret = 0;
       if (drv->bus->match && !drv->bus->match(dev, drv))//如果总线的mach不存在,或者不匹配,返回0,进行下一次迭代
              goto Done;

       pr_debug("%s: Matched Device %s with Driver %s\n",drv->bus->name, dev->bus_id, drv->name);
       dev->driver = drv;//总线的匹配函数返回匹配成功了,设备的驱动指针指向驱动数据结构
       if (drv->probe) {//调用驱动程序中的probe函数,初始化设备
              ret = drv->probe(dev);
              if (ret) {//调用probe出现错误,安全返回
                     dev->driver = NULL;
                     goto ProbeFailed;
              }
       }
       device_bind_driver(dev);//把设备邦定到驱动程序中,上面有分析
       ret = 1;//驱动程序找到了,所以返回1,停止迭代
       pr_debug("%s: Bound Device %s to Driver %s\n",drv->bus->name, dev->bus_id, drv->name);
       goto Done;

ProbeFailed:
       if (ret == -ENODEV || ret == -ENXIO) {
              /* Driver matched, but didn't support device or device not found.Not an error; keep going.*/
              //驱动匹配,但是不支持设备,或者没有发现设备,这不是错误,返回0,继续迭代
              ret = 0;
       } else {
              /* driver matched but the probe failed */
              //驱动匹配,但是probe错误
              printk(KERN_WARNING"%s: probe of %s failed with error %d\n",drv->name, dev->bus_id, ret);
       }
Done:
       return ret;
}

device_add_attrs()
static int device_add_attrs(struct bus_type * bus, struct device * dev)
{//设备属性文件的建立
       int error = 0;
       int i;
       if (bus->dev_attrs) {
              for (i = 0; attr_name(bus->dev_attrs); i++) {
                     error = device_create_file(dev,&bus->dev_attrs);//在sysfs中建立文件,在文件系统中分析
                     if (error)
                            goto Err;
              }
       }
Done:
       return error;
Err:
       while (--i >= 0)
              device_remove_file(dev,&bus->dev_attrs);
       goto Done;
}

bus_register()
int bus_register(struct bus_type * bus)
{
       int retval;
       retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);//前面分析过了
       if (retval)
              goto out;
    //#define subsys_set_kset(obj,_subsys)  (obj)->subsys.kset.kobj.kset = &(_subsys).kset
       subsys_set_kset(bus, bus_subsys); //设置总线设备的父kset
       retval = subsystem_register(&bus->subsys);//总线子系统的初始化,具体的上面分析过了
       if (retval)
              goto out;
       kobject_set_name(&bus->devices.kobj, "devices");//设置bus总线设备kset的name
       bus->devices.subsys = &bus->subsys;//设置设备kset的子系统
       retval = kset_register(&bus->devices);//注册kset,下面分析
       if (retval)
              goto bus_devices_fail;
       kobject_set_name(&bus->drivers.kobj, "drivers");//设置bus总线驱动kset的name
       bus->drivers.subsys = &bus->subsys;//设置驱动kset的子系统
       bus->drivers.ktype = &ktype_driver;//设置驱动kset的type
       retval = kset_register(&bus->drivers);//注册kset,下面分析
       if (retval)
              goto bus_drivers_fail;

       klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);//设备链表的初始化
       klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);//驱动链表的初始化
       bus_add_attrs(bus);//总线属性文件的建立

       pr_debug("bus type '%s' registered\n", bus->name);
       return 0;

bus_drivers_fail:
       kset_unregister(&bus->devices);
bus_devices_fail:
       subsystem_unregister(&bus->subsys);
out:
       return retval;
}

kset_register()
int kset_register(struct kset * k)
{
       kset_init(k);//见下面
       return kset_add(k);//上面分析过
}

kset_init()
void kset_init(struct kset * k)
{//初始化kobj和链表,自旋锁
       kobject_init(&k->kobj);//上面分析过
       INIT_LIST_HEAD(&k->list);
       spin_lock_init(&k->list_lock);
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/67451/showart_684634.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP