You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
239 行对unsigned int sglen 赋值,sg->length 实际上就是DMA buffer 的长度.所以显然我们copy<br />
冬冬不能超过这个长度,如果我们还指定了*<strong>of</strong>fset,就表明DMA buffer 中从*<strong>of</strong>fset 开始装,那么就不能<br />
超<br />
过sg->length-*<strong>of</strong>fset.<br />
241 行,由于我们现在还在while 循环中,所以先看第一次执行到241 行,这时cnt 等于0,buflen 就是那<br />
个data buffer 的长度,传进来的是36.sglen 表征了DMA buffer 里边可以装多少,如果sglen 比buflen<br />
要大,那么很好,一次就可以装满,因为这就好比buflen 是一吨沙子,而sglen 则表示装沙车载重两吨或者<br />
更<br />
多,比如三吨.这样244行245行,其作用就是做个标记,比如sglen被用来记录实际装载了多少重量的沙子,<br />
而*<strong>of</strong>fset 则表征了装沙车用了多少了,如果还没卸货下次又要继续往里装那就装吧,反正没满就可以装.那<br />
么如果sglen 比buflen 要小或者刚好够大,那么*<strong>of</strong>fset 肯定就被设为0,因为这一车必然会被装满,要再<br />
装<br />
沙子只能调用下一辆车,所以同时sg 和*index 也自加.<br />
然后来看257 行了,sglen 一开始肯定应该大于0 吧,她表征的是实际装了多少,但是内存管理机制有一个<br />
限制,memcpy 传输不能够跨页,也就是说不能跨page,一次最多就是把本page 的冬冬给copy 走,如果<br />
你<br />
的数据超过了一个page,那你还得再copy 一次或者多次,因为这里咱们用了循环.每一次真正copy 的长<br />
度<br />
用plen 来表征,所以271 行和272 行,cnt 是计数的,所以她要加上一个plen,而sglen 也是一个计数的,<br />
但是她是反着计,所以她每次要减掉一个plen.而p<strong>of</strong>f 和page 一个设为0,一个自加,这个道理很简单,从下<br />
一页开头进行继续copy.而258 行再次调用强大的min()函数也正是为了保证每次copy 不能跨页.260<br />
和266行这对冤家的出现,kmap()和kunmap(),道理也很简单.这对冤家是内核中的内存管理部门提供给<br />
咱们的重要函数,其中kmap()函数的作用就是传递给她一个struct page 指针,她能返回这个page 指针<br />
所指的那个page 的内核虚拟地址,而有了这个page 对应的虚拟地址,加上咱们前面已经知道的偏移量,咱<br />
们就可以调用memcpy 函数来copy 数据了.至于kunmap,古书有云:凡是kmap()建立起来的良好关系<br />
必须由kunmap()来摧毁.<br />
然后,262 到265 行的两个memcpy 无需再讲了.<br />
278 行,返回实际传输的字节数.<br />
至此,usb_stor_access_xfer_buf()这个函数的每一点每一滴都讲完了.让我们欢呼吧!这一刻,我们不<br />
是一个人在战斗.(注:应该说如果不是很有悟性的话,这段代码要看懂还是挺难的,虽说不至于让你哭得花枝<br />
乱颤,但也足以令你看得眼花缭乱.正式版中关于这个函数应该有一个比较好的图解,来描述这个双重循环,<br />
须知外循环是按sg entry 来循环,即一个sg entry 循环一次,而内循环是按page 来循环,我们说过,一个<br />
sg entry 可以有多个page,而因为我们没有办法跨page 映射,所以只能每个page 映射一次,所以才需要<br />
循环.)<br />
138<br />
回到usb_stor_set_xfer_buf()中来,也只剩下一句话了,如果我们要传递的36 个字节还不足以填满这<br />
辆装沙车的话,那就让我们记录下这辆车还能装多少沙子吧,srb->resid 正是扮演着这个记录者的角色.<br />
然后我们回到fill_inquiry_response()中来,一看,嗬,这个函数也结束了.我们再一次回到了那个不死的<br />
精灵进程,usb_stor_control_thread()中来,这个函数俨然就像当年圣斗士星矢中的不死鸟一辉,总也死<br />
不了,隔一会又会出现.对于INQUIRY 命令,咱们在fill_inquiry_response()之后,把srb->result 设为了<br />
SAM_STAT_GOOD,她是scsi 系统里边定义的一个宏,include/scsi/scsi.h 中:<br />
117 /*<br />
118 * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft<br />
119 * T10/1561-D Revision 4 Draft dated 7th November 2002.