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

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

2011-05-18 11:57 239 查看
至此,我们已经跟踪了mmc/sd卡驱动的注册。。我们接着来看插入拔除卡的中断处理函数:

static
irqreturn_t s3cmci_irq_cd(
int
irq,
void
*
dev_id)

{

struct
s3cmci_host *
host =
(
struct
s3cmci_host *
)
dev_id;

dbg(
host,
dbg_irq,
"card detect/n"
)
;

mmc_detect_change(
host-
>
mmc,
500)
;

return
IRQ_HANDLED;

}



见,这里也会调用mmc_detect_change。。。我们跟着前面的分析来到mmc_setup这里,此时mmc_setup调用
mmc_discover_cards。Create a mmc_card entry for each discovered card,add
new card to
list.同时还会调用mmc_read_switch_caps或者mmc_process_ext_csds来实现对大容量卡的支持(>4G)

跟着程序的流程我们来到

if (!mmc_card_present(card) && !mmc_card_dead(card)) {

if (mmc_register_card(card))

来看

int
mmc_register_card(
struct
mmc_card *
card)

{

int
ret;

snprintf(
card-
>
dev.
bus_id,
sizeof
(
card-
>
dev.
bus_id)
,

"%s:%04x"
,
mmc_hostname(
card-
>
host)
,
card-
>
rca)
;

ret =
device_add(
&
card-
>
dev)
;

if
(
ret =
=
0)
{

if
(
mmc_card_sd(
card)
)
{

ret =
device_create_file(
&
card-
>
dev,
&
mmc_dev_attr_scr)
;

if
(
ret)

device_del(
&
card-
>
dev)
;

}

}

return
ret;

}



函数在mmc_sysfs.c中定义。
device_add(&card->dev)将到相应总线mmc_bus_type上去搜索相应驱动。找到驱动后就设置
dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数

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)
;

}


mmc_bus_probe会调用mmc_blk_probe

mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程mmc_queue_thread()。

static
int
mmc_blk_probe(
struct
mmc_card *
card)

{

struct
mmc_blk_data *
md;

int
err;

/*

* Check that the card supports the command class(es) we need.

*/

if
(
!
(
card-
>
csd.
cmdclass &
CCC_BLOCK_READ)
)

return
-
ENODEV;

md =
mmc_blk_alloc(
card)
;
//

if
(
IS_ERR(
md)
)

return
PTR_ERR(
md)
;

err =
mmc_blk_set_blksize(
md,
card)
;

if
(
err)

goto
out;

printk(
KERN_INFO "%s: %s %s %lluKiB %s/n"
,

md-
>
disk-
>
disk_name,
mmc_card_id(
card)
,
mmc_card_name(
card)
,

(
unsigned
long
long
)
(
get_capacity(
md-
>
disk)
>
>
1)
,

md-
>
read_only ?
"(ro)"
:
""
)
;

mmc_set_drvdata(
card,
md)
;

add_disk(
md-
>
disk)
;

return
0;

out:

mmc_blk_put(
md)
;

return
err;

}


struct mmc_blk_data封装了struct gendisk 与 struct mmc_queue,而struct mmc_queue封装了struct mmc_card与struct request。

static
struct
mmc_blk_data *
mmc_blk_alloc(
struct
mmc_card *
card)

{

struct
mmc_blk_data *
md;

int
devidx,
ret;

devidx =
find_first_zero_bit(
dev_use,
MMC_NUM_MINORS)
;

if
(
devidx >
=
MMC_NUM_MINORS)

return
ERR_PTR(
-
ENOSPC)
;

__set_bit(
devidx,
dev_use)
;

md =
kmalloc(
sizeof
(
struct
mmc_blk_data)
,
GFP_KERNEL)
;

if
(
!
md)
{

ret =
-
ENOMEM;

goto
out;

}

memset
(
md,
0,
sizeof
(
struct
mmc_blk_data)
)
;

/*

* Set the read-only status based on the supported commands

* and the write protect switch.

*/

md-
>
read_only =
mmc_blk_readonly(
card)
;
//写保护

/*

* Both SD and MMC specifications state (although a bit

* unclearly in the MMC case) that a block size of 512

* bytes must always be supported by the card.

*/

md-
>
block_bits =
9;
//块大小

md-
>
disk =
alloc_disk(
1 <
<
MMC_SHIFT)
;

//分配struct gendist,驱动程序不能自己动态分配该结构,而是必须调用

//alloc_disk,其参数为次设备号数目,注意了,是次设备号数目,不是次设备号

if
(
md-
>
disk =
=
NULL
)
{

ret =
-
ENOMEM;

goto
err_kfree;

}

spin_lock_init(
&
md-
>
lock)
;

md-
>
usage =
1;

ret =
mmc_init_queue(
&
md-
>
queue
,
card,
&
md-
>
lock)
;
//

if
(
ret)

goto
err_putdisk;

md-
>
queue
.
prep_fn =
mmc_blk_prep_rq;

md-
>
queue
.
issue_fn =
mmc_blk_issue_rq;

md-
>
queue
.
data =
md;

//上面设置了请求队列,现在就可以初始化及安装相应的gendisk结构了

md-
>
disk-
>
major    =
major;

md-
>
disk-
>
first_minor =
devidx <
<
MMC_SHIFT;

md-
>
disk-
>
fops =
&
mmc_bdops;

md-
>
disk-
>
private_data =
md;

md-
>
disk-
>
queue
=
md-
>
queue
.
queue
;

md-
>
disk-
>
driverfs_dev =
&
card-
>
dev;

/*

* As discussed on lkml, GENHD_FL_REMOVABLE should:

*

* - be set for removable media with permanent block devices

* - be unset for removable block devices with permanent media

*

* Since MMC block devices clearly fall under the second

* case, we do not set GENHD_FL_REMOVABLE.  Userspace

* should use the block device creation/destruction hotplug

* messages to tell when the card is present.

*/

sprintf
(
md-
>
disk-
>
disk_name,
"mmcblk%d"
,
devidx)
;

blk_queue_hardsect_size(
md-
>
queue
.
queue
,
1 <
<
md-
>
block_bits)
;

/*

* The CSD capacity field is in units of read_blkbits.

* set_capacity takes units of 512 bytes.

*/

set_capacity(
md-
>
disk,
card-
>
csd.
capacity <
<
(
card-
>
csd.
read_blkbits -
9)
)
;

return
md;

err_putdisk:

put_disk(
md-
>
disk)
;

err_kfree:

kfree(
md)
;

out:

return
ERR_PTR(
ret)
;

}


至此,驱动向系统添加了一个块设备。

请求处理过程:

mmc_request--->mmc_queue_thread----->mmc_blk_issue_rq---->mmc_wait_for_req--->mmc_start_request---->s3cmci_requ
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: