对于SD驱动子系统里,只有一部分和硬件挂钩,就是Host主机控制层,对于block块设备层存软件的,就是实现一个块设备结构体,然后注册一个请求处理函数而已(这个函数会最终会调用到主机控制器层的请求函数),这个共性的不需要我们考虑。而对于Core核心层来说,和SD卡是紧密相关,但是这是协议层,仅仅实现协议,例如初始化卡的需要哪几部分,读取卡需要几步骤等,这里只是实现协议层,没有硬件操作。但是这协议层实现的函数会调用到Host核心层来实现发送命令数据等。
队以我们来说,如果想添加其他卡的操作,就修改core层,如果想添加MMC/SD控制器那就修改Host层,我们现在讨论主机控制层。主机控制层的任务:实现协议的底层实现。
看看Host层的架构:
首先Host层基于platform平台,通过probe获取主机控制器的寄存器地址和中断号:
static struct platform_driver s3cmci_driver = {
.probe = s3cmci_probe,
};
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
}
static void __exit s3cmci_exit(void)
{
platform_driver_unregister(&s3cmci_driver);
}
static int __devinit s3cmci_probe(struct platform_device *pdev)
1、获取主机控制器的寄存器基地址和中断号,注册中断,使能时钟。如果有使用DMA还有申请DMA;
2、分配设置注册mmc_host结构体,这是主机控制器的操作结构体,主要就三个函数:
mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
mmc->ops = &s3cmci_ops;
ret = mmc_add_host(mmc);
mmc_alloc_host函数在核心层实现的,最为核心的函数就是INIT_DELAYED_WORK(&host->detect, mmc_rescan)勘测函数绑定,mmc_add_host函数里最核心函数就是调用mmc_schedule_delayed_work(&host->detect, delay)函数,也就是调用mmc_rescan函数。如果当前没有卡那就在mmc_rescan里直接返回,如果有卡就会发送连锁反应。这个mmc_rescan函数还会在中断发生,素以如果插入卡也会调用。这个函数会枚举卡并通过mmc_attach_mmc函数初始化卡,最主要就是调用mmc_init_card和mmc_add_card函数进而触发块设备驱动block里的probe函数被调用而初始化好块设备,进而把块设备和主机控制器都运作起来。
对于Host层另一个重要任务就是实现mmc->ops = &s3cmci_ops操作函数了,里面包含协议用到的硬件处理层:
static struct mmc_host_ops s3cmci_ops = {
.request = s3cmci_request, //发送请求数据硬件操作函数
.set_ios = s3cmci_set_ios, //设置时钟电压等
.get_ro = s3cmci_get_ro, //判断卡是否为只读
.get_cd = s3cmci_card_present, //判断卡是否在插槽
.enable_sdio_irq = s3cmci_enable_sdio_irq, //使能中断
};
对于请求来说块设备的请求处理函数还调用核心层,核心层会调用mmc_host_ops 的请求:
static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
//实现把请求(也就是命令)发送
//启动数据传输模式:FIFO/DMA,,要初始化好,然后使能中断
}
当命令发完之后有数据读写时候会产生中断(在probe注册了)
static irqreturn_t s3cmci_irq(int irq, void *dev_id)
{
//判断是不是发送接收数据中断,哈市完成中断,还是出错中断,然后进行处理
例如FIFO:
if (host->pio_active == XFER_WRITE)
do_pio_write(host);
if (host->pio_active == XFER_READ)
do_pio_read(host);
}
到这里请求就结束了。剩下的几个函数也是一样,都是硬件操作:
static int s3cmci_get_ro(struct mmc_host *mmc)
{
ret = gpio_get_value(pdata->gpio_wprotect) ? 1 : 0; //读取引脚值就知道卡是否处于保护状态
............
}
static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
//电源on/off设置,时钟频率从设置、SD卡总线宽度设置
}
static int s3cmci_card_present(struct mmc_host *mmc)
{
//判断一个引脚电平就可以知道卡是否在卡槽
}