您的位置:首页 > 运维架构 > Linux

linux2.6.20 sd/mmc卡驱动学习日记1(基于s3c2440)

2011-05-18 09:30 253 查看
首先,我们来看Makefile文件吧,Makefile中文件的目标文件的顺序是很重要的,因为这个会涉及到模块的依赖关系,比如说,如果这些源文件中
有module_init(),则这些module_init就按在Makefile中的顺序链接进内核,之后也按照链接的顺序进行调用。根据我们的内核
配置选项,将要编译进内核的文件就只有mmc.c,mmc_sysfs.c,mmc_block.c,mmc_queue.c,s3cmci.c这几个文
件。其中mmc.c与mmc_queue.c主要是定义了一些其他文件中将要使用的函数,我们暂时不管它。接下来,我们来分析mmc_sysfs.c

我们先来看mmc_init(),这是系统启动后将要调用的,在mmc_init函数中,主要完成3项工作 :

workqueue = create_singlethread_workqueue("kmmcd");//创见一个单线程的工作队列

bus_register(&mmc_bus_type);//注册总线

class_register(&mmc_host_class);//注册mmc_host_class

mmc_bus_type的定义为:

static
struct
bus_type mmc_bus_type =
{

.
name        =
"mmc"
,

.
dev_attrs    =
mmc_dev_attrs,

.
match        =
mmc_bus_match,

.
uevent        =
mmc_bus_uevent,

.
probe        =
mmc_bus_probe,

.
remove
=
mmc_bus_remove,

.
suspend    =
mmc_bus_suspend,

.
resume        =
mmc_bus_resume,

}
;


这里,我们主要关注mmc_bus_match与mmc_bus_probe,此两函数将要在device_register和driver_register向总线注册设备的时候被调用。

static
int
mmc_bus_match(
struct
device *
dev,
struct
device_driver *
drv)

{

struct
mmc_card *
card =
dev_to_mmc_card(
dev)
;

return
!
mmc_card_bad(
card)
;

}

#
define
mmc_card_bad(
c)
(
(
c)
-
>
state&
(
MMC_STATE_BAD)


可见,对于mmc总线,mmc_bus_match是通过返回struct mmc_card中的状态标示state位来实现的。

static
int
mmc_bus_probe(
struct
device *
dev)

{

struct
mmc_driver *
drv =
to_mmc_driver(
dev-
>
driver)
;

struct
mmc_card *
card =
dev_to_mmc_card(
dev)
;

return
drv-
>
probe(
card)
;

}


在使用bus_register之后,我们可以在sysfs的/sys/bus目录里看到它

static
struct
class
mmc_host_class =
{

.
name        =
"mmc_host"
,

.
dev_release    =
mmc_host_classdev_release,

}
;

class_register之后,在/
sys/
class目录下将出现mmc_host目录


---------------------------------------------------------------------------------

接下来,我们看mmc_block.c,还是从初始化函数mmc_blk_init开始分析

static
int
__init mmc_blk_init(
void
)

{

int
res =
-
ENOMEM;

res =
register_blkdev(
major,
"mmc"
)
;

if
(
res <
0)
{

printk(
KERN_WARNING "Unable to get major %d for MMC media: %d/n"
,

major,
res)
;

goto
out;

}

if
(
major =
=
0)

major =
res;

return
mmc_register_driver(
&
mmc_driver)
;

out:

return
res;

}


在mmc_blk_init中, register_blkdev(major, "mmc")的作用是注册一个块设备。如果传递的major为0,这内核将分派一个新的主设备号给设备。

register_blkdev的功能比较少,一是动态分配设备号,二是在/proc/devices中创建一个入口项 。故通过它之后,系统还是不能使用块设备的。

接着我们看

return mmc_register_driver(&mmc_driver);

mmc_register_driver在mmc_sysfs.c中定义:

static
struct
mmc_driver mmc_driver =
{

.
drv        =
{

.
name    =
"mmcblk"
,

}
,

.
probe        =
mmc_blk_probe,

.
remove
=
mmc_blk_remove,

.
suspend    =
mmc_blk_suspend,

.
resume        =
mmc_blk_resume,

}
;

int
mmc_register_driver(
struct
mmc_driver *
drv)

{

drv-
>
drv.
bus =
&
mmc_bus_type;

return
driver_register(
&
drv-
>
drv)
;

}


这两句代码比较好理解吧。在注册一个struct driver之前,都要先设置它的bus,类似的,在platform_driver_register中我们也可所以看到:

drv->driver.bus=&platform_bus_type

driver_register将到相应总线mmc_bus_type上去搜索相应设备。找到设备后就设置dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数.

我们跟踪driver_register(&drv->drv),它会调应bus_add_driver。

int
bus_add_driver(
struct
device_driver *
drv)

{

.
.
.

.
.
.

error
=
kobject_set_name(
&
drv-
>
kobj,
"%s"
,
drv-
>
name)
;

if
(
error
)

goto
out_put_bus;

drv-
>
kobj.
kset =
&
bus-
>
drivers;

if
(
(
error
=
kobject_register(
&
drv-
>
kobj)
)
)

goto
out_put_bus;

error
=
driver_attach(
drv)
;

.
.
.

.
.
.

}


在调用kobject_register之后,我们可以在/sys/bus/mmc/driver目录下看到mmcblk文件driver_attach
函数会遍历相应总线(mmc_bus_type)上的dev,对这些dev执行总线的match函数(mmc_bus_match)。如果match成
功,它会调用mmc_bus_type总线的probe函数mmc_bus_probe(如果总线的probe存在的话).我们在以上走过的流程中可以看
到,我们并没有向总线添加任何设备,故mmc_bus_probe是不会调用的。但相应的driver已经注册到系统了。

那么,现在mmc_block.c中的分析就先暂时到此为止。。。不过,等会儿我们还会继续回到这个文件的。。

----------------------------------未完待续-----------------------------------
http://blog.chinaunix.net/space.php?uid=14782631&do=blog&id=111888
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: