我们接着来到s3cmci.c文件
s3cmci_init----->platform_driver_register(&s3cmci_driver_2440)------------>s3cmci_probe_2440----->s3cmci_probe
在s3cmci_probe中主要是分配及初始化
struct mmc_host *mmc;
struct s3cmci_host
*host;
这两个结构体。分配DMA通道,注册irq中断。
以下对个别函数的作用进行说明:
1: clk_get
系统初始化的时候外围总线上的设备不是都给时钟的,主要是为了省电。
在2.6.20中,我们在文件arch/arm/mach-s3c2410/s3c2410-clock中可以看到nand,sdi,adc,i2c,iis这些是不给时钟的
lcd,gpio,usb,uart这些是给时钟的
clk_get在arch/arm/mach-s3c2410/clock.c中定义
2: mmc_alloc_host
mmc_alloc_host分配sizeof(struct
mmc_host)+extra这么大的空间,并做以下初始化
host = mmc_alloc_host_sysfs(extra,
dev);
host->parent = dev;
host->class_dev.parent =
dev;
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_LIST_HEAD(&host->cards);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
* By
default, hosts do not support SGIO or large requests.
* They have to set
these according to their abilities.
host->max_hw_segs =
1;
host->max_phys_segs = 1;
host->max_sectors = 1 <<
(PAGE_CACHE_SHIFT - 9);
host->max_seg_size =
PAGE_CACHE_SIZE;
3:
mmc_add_host
调用mmc_add_host的最终结果是device_add(&host->class->dev)(所以在/sys/class/mmc/目录下出现mmc0文件)。
并会调用mmc_power_off(host);mmc_detect_change(host, 0);
mmc_power_off函数比较简单,顾名思义,它是让SD/MMC卡停止工作的,相应的,此函数就会配置相应的IO口以及时钟等。
我们来看看mmc_detect_change函数吧。
void
mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
mmc_schedule_delayed_work(&host->detect, delay);
}
int
mmc_schedule_delayed_work(struct delayed_work *work, unsigned long
delay)
{
return queue_delayed_work(workqueue, work,
delay);
}
queue_delayed_work把host->detect提交到workqueue工作对列中。
相应定义:
INIT_DELAYED_WORK(&host->detect,
mmc_rescan);
workqueue =
create_singlethread_workqueue("kmmcd");
所以,当此delayed_work执行的时候,mmc_rescan将会被调用
static void mmc_rescan(struct work_struct *work) { struct mmc_host *host = container_of(work, struct mmc_host, detect.work);//返回指向s3cmci_probe中分配的mmc_host结构的指针
struct list_head *l,
*n; unsigned char power_mode;
mmc_claim_host(host); /* 驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用,当前mmc控制器如果被占用,那么
host->claimed = 1;否则为0,如果为1,那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行
mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的物理使用权 */ /* * Check for removed
cards and newly inserted ones. We check for * removed cards first so we
can intelligently re-select the VDD. */ power_mode = host->ios.power_mode; if (power_mode ==
MMC_POWER_ON) mmc_check_cards(host); mmc_setup(host); /* * Some broken cards process CMD1 even
in stand-by state. There is * no reply, but an ILLEGAL_COMMAND error is
cached and returned * after next command. We poll for card status here
to clear any * possibly pending error. */ if (power_mode ==
MMC_POWER_ON) mmc_check_cards(host);
if (!list_empty(&host->cards))
{ /* * (Re-)calculate the
fastest clock rate which the * attached cards and the host
support. */ host->ios.clock = mmc_calculate_clock(host); mmc_set_ios(host); }
mmc_release_host(host);
list_for_each_safe(l,
n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l);
/* * If this is a new and good card,
register it. */ if (!mmc_card_present(card) && !mmc_card_dead(card))
{ if (mmc_register_card(card)) mmc_card_set_dead(card); else mmc_card_set_present(card); }
/*s * If this card is dead, destroy
it. */ if
(mmc_card_dead(card))
{ list_del(&card->node); mmc_remove_card(card); } }
/* * If we discover that there are no
cards on the * bus, turn off the clock and power
down. */ if (list_empty(&host->cards)) mmc_power_off(host); }
|
起初,power_mode
= MMC_POWER_OFF,故第一个mmc_check_cards(host)是不会执行的。但mmc_setup函数中设置了power_mode =
MMC_POWER_ON。故第二个mmc_check_cards(host)是会执行的。
在mmc_setup中,会调用mmc_discover_cards.如果发现有卡,则add
new card to
list.
因为现在没有发现卡,host->card=NULL,故mmc_check_cards与mmc_rescan中的list_for_each_safe循环体中的内容也是不会执行的。
static void mmc_check_cards(struct mmc_host *host) { struct list_head *l,
*n;
mmc_deselect_cards(host);// Ensure that no card is
selected.
list_for_each_safe(l,
n, &host->cards) { struct mmc_card *card = mmc_list_to_card(l); struct mmc_command cmd; int err;
cmd.opcode = MMC_SEND_STATUS; cmd.arg
= card->rca << 16; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); if (err ==
MMC_ERR_NONE) continue;
mmc_card_set_dead(card); } }
|
执行完s3cmci_probe后,在终端会有以下信息:
s3c2410-sdi
s3c2410-sdi: powered down.
s3c2410-sdi s3c2410-sdi: initialisation
done.
s3c2410-sdi s3c2410-sdi: running at 0kHz (requested:
0kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested:
197kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested:
197kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested:
197kHz).
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #2 op:APP_CMD(55)
arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #3
op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT]
#4 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi:
CMD[TIMEOUT] #5 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi
s3c2410-sdi: CMD[TIMEOUT] #6 op:ALL_SEND_OCR(1) arg:0x00000000
flage
s3c2410-sdi s3c2410-sdi: powered
down.
------------------------------------未完待续------------------------------------