在前一篇写了关于SD卡的驱动,但是还是比较简单。最近在一个车载项目上遇到快速Suspend/Resume的问题。客户需要在频率很高的Suspend/Resume之后SD卡能够保证文件的续传。这样又得更加深入研究SDBus层的内容了。
首先要描述一下SD卡文件续传的问题,在系统Suspend的时候,系统为了节省电能要求SD在Sleep状态下不供电。但是等到resume起来之后肯定是没有办法续传的。为了解决这个问题,在SD的PowerDown的过程中,将SD的VCC关掉。在SD的PowerUp中执行一次仿拔插(fake remove/insert)。也就是在系统起来的过程中,先执行一次Remove卡的动作,再执行一次卡插入的东西。但是这些只是程序来做,硬件上并没有卡的插拔动作。为什么要这样子做呢?因为在SD卡能够传输数据前首先要进行识别(Identification)的过程。之后转到传输模式(Transfer Mode)。在Suspend时关闭VCC那么卡等于已经不处于传输模式,那么Resume起来之后自然没法续传。那么根据这个才需要做仿拔插的动作,这样才会重新进行卡的识别过程,使卡进入传输模式。当然这只是保证卡能够续传的一个方面,要想续传还需要文件系统支持才可以,因为在续传之前对于文件的句柄都是由文件系统所管理的。刚好CE的文件系统管理器提供了这个机制,在执行仿拔的时候系统会UnMount SD卡,但是系统并不会立刻UnMount SD卡,而是需要等待一个Delay时间。在这个时间到了之前卡重新被Mount上的话SD卡就不会别Unmount掉了,如果时间到卡还没有被Mount那么这时卡才被真正的UnMount。有了这个机制,才可以进行文件的续传。
然而在很快的进行Suspend/Resume之后,发现在最后一次Resume起来之后,那个Delay时间已经过了,那么SD卡被UnMount自然无法进行续传了。后来又发现即便这个Delay时间满足要求,在文件系统部分也会存在问题。文件系统会去判断一个Vol的句柄,如果不可用就会去等待,时间到就直接退出了。所以对于这个问题,这两个点是关键点。
不过这个问题已经给我同事解了。在StorageManager中去判断卡的状态,通过它来决定是否要真正的UnMount卡。这样即便Delay时间到只要卡的状态OK,就忽略UnMount的动作。这样就可以解决Delay时间的问题。那么文件系统的问题如何解决呢?
在文件系统判断Handler的地方,通过Vol的名字来判断如果是SD 卡就会一直Hold住,而其他的块设备则不受影响。
虽然问题已经解决,但是还是研究了一下Bus层的代码。而且修改了一下也有些效果。
首先是看总体的驱动结构:
最上面是:CSDHostContainer
下面就是CSDHost,CSDSlot。这三个部分在操作过程中基本没什么变化。
在下面还有CSDDevice 和 DeviceFolder。这两个是动态的,卡插入后创建相应的对象,卡移除后删除。
那么如何修改Bus层来解决上面续传的问题呢?在卡插入的过程中会创建CSDDevice的对象,那么在仿拔的过程不去删除这个
CSDDevice的对象,接下来在仿插的过程中,当然也会再创建一个CSDDevice的对象,实际我们并不需要这个对象。它的作用只是让卡进入传输模式。等卡进入传输模式后删除掉后一个CSDDevice的对象,恢复最早的那个CSDDevice的对象。这样就可以不用到StorageManager部分来控制了。那么续传的过程还需要设置一个等待,因为文件系统的部分没有Delay,所以系统一Resume起来马上会执行续传操作,这时可能在Bus层还没有恢复回来,所以在Memory层的IoControl加一个Delay来解决。
虽然这样修改可以实现不动StorageManager来实现,但是还有部分问题没有解决。这样修改之后快速Suspend/Resume之后还是会有问题,同时如何判断Resume后卡是不是换过也需要进行判断,而这部分在StorageManager中去判断卡的部分做的很完善。
今天又进行了一些尝试,发现在快速Suspend/Resume之后虽然用了上面说的方法可以不涉及StorageManager但是发现还是会无法使用SD卡,后来发现在最后一次Resume起来后实际的Bus层还没有全部结束,而在这时电源管理会通过Sdmemory的Iocontrol去Set Power。这部分在SD卡还没有真正准备好的情况下会Fail。不过也好解决,只需要简单得返回一个D0的状态就好了。因为实际的SD Power是由XXX_PowerDown和XXX_PowerUp来管理的。
但是这样改了之后还是有问题,在读取的时候还会有Error 31出现,不过现在也有了一个思路,就是在执行伪拔插时记录进入的次数,而在SDSlot中去判断这个次数,如果不是最后一次的话简单的返回一个TRUE,如果是最好一次进入的话执行卡的识别操作,这样会节省很多卡识别过程的时间。这样做的话还需要在Sdmemory中创建一个等待的事件将文件系统的读写Hold住,等到真正卡准备好之后再运行。