整理sd卡驱动在linux 2.6.24上的实现简易心得
1.mmc_rescan 当GPIO8发生sd卡插入动作后,进入pxamci_detect_irq()中断,进而触发mmc_rescan检卡work queue工作队列
2.对于sdio设备 host->bus_ops = mmc_sdio_ops;
对于sd设备 host->bus_ops = mmc_sd_ops;
对于mmc设备 host->bus_ops = mmc_ops;
如果检测到插入sd口的设备不是上述3种设备,那么这次mmc_rescan将不能建立任何设备,关闭sd口电源,之后退出.
如果检测到的是sdio设备,那么card将被放到mmc_bus_type总线,同时sdio_funcs会被放到sdio_bus_type总线上,去匹配sido_func驱动
如果检测到的是sd设备,那么card将被放到mmc_bus_type总线,去匹配mmc_bus_type总线上的mmc驱动
如果检测到的是mmc设备,那么card也和sd设备一样将被放到mmc_bus_type总线上.
只有host不会挂载到总线上,插入的sd设备是一定会被登记到mmc_bus_type总线上,如果是sdio设备,那么同时sdio设备的sdio_funcs会被放到sdio_bus_type总线上,去匹配sido_func驱动
3.当host发送完数据之后,命令完成之后,以及sdio_int中断上来之后,cpu会触发pxamci_irq,去集中处理
4.对于主host控制器的同一读写函数为
mmc_host->ops = pxamci_ops
static const struct mmc_host_ops pxamci_ops = {
.request = pxamci_request,
.get_ro = pxamci_get_ro,
.set_ios = pxamci_set_ios,
.enable_sdio_irq= pxamci_enable_sdio_irq,
};
ps:
因为mmc主控制器只有一个,被众多驱动和设备共享,同时对于同一设备,因为数据发送是异步进行的,所以当前如果需要发送数据,那么之前的数据可能因为还没有发送完成,而仍然占用着mmc主控制器的物理寄存器,所以为了保证对物理设备的唯一共享,不扰乱物理通道上的数据序列,驱动中使用 mmc_claim_host(host);来得知,当前mmc控制器是否被占用,当前mmc控制器如果被占用,那么host->claimed = 1;否则为0,如果为1,那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的物理使用权 [gliethttp_20080630].
ps1:
不过在pxamci_irq实际中断处理过程中,也就是cmd,data等传输完毕之后,都是会调用pxamci_finish_request()来wake_up唤醒阻塞等待的mmc_wait_done()回调函数,这也是命令执行函数mmc_wait_for_cmd()使用的阻塞等待当前命令结束的方法,之所以这样,是因为有些操作需要驱动去直接操作mmc控制器的寄存器,如果不这样作,就有可能和正在传输中的data中断发生数据和cmd等的命令冲突,这样就使得mmc主控制器上的数据发生混乱,这是绝对不允许的,所以就只能使用这种阻塞方式,来一个一个的完成操作,肯定是不能并行的搞[gliethttp_20080630].
/
发现了两篇讲SD/MMC卡驱动的文章,觉得不错,转了过来,谢谢原作者
文一:FROM:http://blog.chinaunix.net/u2/69999/showart_734099.html
关于linux 2.6 mmc/sd驱动
linux 2.6 中的mmc/sd驱动分为以下几方面的内容
1. sysfs 层的总线类型处理: 注册一组 mmc 类型处理函数, 标志为 "mmc"
具体在mmc_sysfs.c文件中实现
2. mmc/sd 快设备管理:注册一个块设备和一组 mmc 总线类型的 driver 子函数, 实现块设备的队列管理等
drivers/mmc/mmc_block.c
3. mmc/sd host管理: 实现 host 的管理
. drivers/mmc/mmc.c:主要的 MMC command 與 protocol 實作。
4. 针对特定的mcu实现一个host驱动实例:主要是注册一个 host实体,中断处理函数,io设置函数,请求处理函数等
以上1.2.3基本是不需要修改的,需要处理的就是 4.要做的工作.当有卡插入时,由4中实现的插卡中断激活卡初始化程序和总线探测函数. 由mmc总线探测函数会调用块设备的探测函数,在卡设备探测函数中会初始化块设备的请求队列和注册一个gendisk实体(以后文件系统会通过 gendisk实体访问 mmc 块设备),同时在sysfs中建立真正的 mmc/sd 设备.块设备通过具体的 host 注册的io设置函数和请求函数与具体的host通讯.
后面的文章将具体对几个部分进行分析
-----------------------------------------------------------------------------
文二:
FROM:http://blog.chinaunix.net/u1/42456/showart_516030.html
最近要让s3c2440在linux2.6.18上 支持4G的SD卡.
原文地址:http://linux4u.wikidot.com/mmc-controller-driver
==============================================================
linux-2.6.2x的mmc驱动与linux-2.6.1x的mmc驱动的区别
在linux-2.6.2x中,mmc驱动用到的block_device_operations结构已重新定义,请看:
linux-2.6.1x:
struct block_device_operations { int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); struct module *owner;};linux-2.6.2x
struct block_device_operations { int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); long (*compat_ioctl) (struct file *, unsigned, unsigned long); int (*direct_access) (struct block_device *, sector_t, unsigned long *); int (*media_changed) (struct gendisk *); int (*revalidate_disk) (struct gendisk *); int (*getgeo)(struct block_device *, struct hd_geometry *); struct module *owner;};
注意到新版本的block驱动接口结构增加了gntgeo成员,使调用者可以直接调用此函数获得设备的几何结构。
工作流程:
mmc驱动主要文件包括
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/
内核启动时,首先执行core/core.c的mmc_init,注册mmc、sd总线,以及一个host class设备。接着执行card/block.c中,申请一个块设备。
数据结构:
mmc总线操作相关函数,由于mmc卡支持多种总数据线,如SPI、SDIO、8LineMMC,而不同的总线的操作控制方式不尽相同,所以通过此结构与相应的总线回调函数相关联。
//总线操作结构struct mmc_bus_ops { void (*remove)(struct mmc_host *); void (*detect)(struct mmc_host *); int (*sysfs_add)(struct mmc_host *, struct mmc_card *card); void (*sysfs_remove)(struct mmc_host *, struct mmc_card *card); void (*suspend)(struct mmc_host *); void (*resume)(struct mmc_host *);};// mmc卡的总线操作 core/mmc.cstatic const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, .sysfs_add = mmc_sysfs_add, .sysfs_remove = mmc_sysfs_remove, .suspend = mmc_suspend, .resume = mmc_resume,};// sd卡的总线操作 core/sd.cstatic const struct mmc_bus_ops mmc_sd_ops = { .remove = mmc_sd_remove, .detect = mmc_sd_detect, .sysfs_add = mmc_sd_sysfs_add, .sysfs_remove = mmc_sd_sysfs_remove, .suspend = mmc_sd_suspend, .resume = mmc_sd_resume,};// sdio的总线操作 core/sdio.cstatic const struct mmc_bus_ops mmc_sdio_ops = { .remove = mmc_sdio_remove, .detect = mmc_sdio_detect,};关于总线操作的函数:
.detect,驱动程序经常需要调用此函数去检测mmc卡的状态,具体实现是发送CMD13命令,并读回响应,如果响应错误,则依次调用.remove、detach_bus来移除卡及释放总线。
总体架构:
kernel启动时,先后执行mmc_init()及mmc_blk_init(),以对mmc设备及mmc块模块进行初始化。
然后在挂载mmc设备驱动时,执行驱动程序中的xx_mmc_probe(),检测host设备中挂载的sd设备。此时probe函数会创建一个host设备,然后开启一个延时任务mmc_rescan()。
驱动挂载成功后,mmc_rescan()函数被执行,然后对卡进行初始化(步骤后面详细讲述)。
假如扫描到总线上挂有有效的设备,就调用相对应的函数把设备装到系统中,mmc_attach_sdio()、mmc_attach_sd()、mmc_attach_mmc()这三个函数分别是装载sdio设备,sd卡和mmc卡的。
在 sd卡中,驱动循环发送ACMD41、CMD55给卡,读取OCR寄存器,成功后,依次发送CMD2(读CID)、CMD3(得到RCA)、CMD9(读 CSD)、CMD7(选择卡)。后面还有几个命令分别是ACMD41&CMD51,使用CMD6切换一些功能,如切换到高速模式。
经过上述步骤,已经确定当前插入的卡是一张有效、可识别的存储卡。然后调用mmc_add_card()把存储卡加到系统中。正式与系统驱动连接在一起。
卡设备加到系统中后,通知mmc块设备驱动。块设备驱动此时调用probe函数,即mmc_blk_probe()函数,mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程 mmc_queue_thread()。
mmc_rescan:mmc_rescan()函数是在驱动装载的时候,由驱动xx_mmc_probe()调用 mmc_alloc_host()时启动的一个延时任务。 xx_mmc_probe()->mmc_alloc_host()->INIT_DELAYED_WORK(&host->detect, mmc_rescan);
当
core部分
1、取得总线
2、检查总线操作结构指针bus_ops,如果为空,则重新利用各总线对端口进行扫描,检测顺序依次为:SDIO、Normal SD、MMC。当检测到相应的卡类型后,就使用mmc_attach_bus()把相对应的总线操作与host连接起来。
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops){ ... host->bus_ops = ops; ...}3、初始化卡接以下流程初始化:
a、发送CMD0使卡进入IDLE状态
b、发送CMD8,检查卡是否SD2.0。SD1.1是不支持CMD8的,因此在SD2.0 Spec中提出了先发送CMD8,如响应为无效命令,则卡为SD1.1,否则就是SD2.0(请参考SD2.0 Spec)。
c、发送CMD5读取OCR寄存器。
d、发送ACMD55、CMD41,使卡进入工作状态。MMC卡并不支持ACMD55、CMD41,如果这步通过了,则证明这张卡是SD卡。
e、如果d步骤错误,则发送CMD1判断卡是否为MMC。SD卡不支持CMD1,而MMC卡支持,这就是SD和MMC类型的判断依据。
f、如果ACMD41和CMD1都不能通过,那这张卡恐怕就是无效卡了,初始化失败。
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/unbutun/archive/2009/03/26/4027289.aspx
好的url:
http://apps.hi.baidu.com/share/detail/5738180
http://edu.codepub.com/2010/0611/23407_7.php
http://blog.chinaunix.net/u3/110130/showart_2147127.html
http://www.china-cto.cn/cu/44438s.html
http://cjc.javaeye.com/blog/404754
http://herbertbt.blog.163.com/blog/static/5726658220097113421582/