- 论坛徽章:
- 0
|
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 |
|