usb_stor_bulk_transfer_sglist()这个函数有一定的蛊惑性,我们前面说过,之所以采用sglist,就是为了提高传输效率.我们更知道,sg的目的就是让一堆不连续的buffers一次DMA操作就都传输出去.其实在usb的故事中,事情并非如此.不过如果你对usb core里边的行为不关心的话,那就无所谓了.有些事情,你不知道也好.
446行,447行,aborting了或者disconnecting了,就不要传递数据了.
然后452行,usb_sg_init()函数被调用,这个函数来自drivers/usb/core/message.c,也就是说,她是usb核心层提供的函数,干嘛用的?初始化sg请求.其第一个参数是struct usb_sg_request结构体的指针.这里咱们传递了us->current_sg的地址给她,这里us->current_sg第一次派上用场,所以咱们需要隆重的介绍一下.在struct us_data中,定义了这么一个成员,struct usb_sg_request current_sg.曾几何时咱们见到过current_urb,这里又来了一个current_sg.也许你感觉很困惑,这很正常,色彩容易让人炫目,文字容易让人迷惑,只有张爱玲对现实的认识是清醒的.其实可以这样理解,之前我们知道struct urb表征的是一个usb request,而这里struct usb_sg_request实际上表示的是一个scatter gather request,从我们非usb核心层的人来看,这两个结构体的用法是一样的.对于每次urb请求,我们所作的只是申请一个结构体变量或者说申请指针然后申请内存,第二步就是提交urb,即调用usb_submit_urb(),剩下的事情usb core就会去帮我们处理了,Linux中的模块机制酷就酷在这里,每个模块都给别人服务,也同时享受着别人提供的服务.就像我们常说的,你站在桥上看风景,看风景的人在楼上看你.明月装饰了你的窗子,你装饰了别人的梦.你要想跟别人协同工作,你只要按照人家提供的函数去调用,把你的指针你的变量传递给别人,其它的你根本不用管,事成之后你人家自然会通知你.同样对于sg request,usb core也实现了这些,我们只需要申请并初始化一个struct usb_sg_request的结构体,然后提交,然后usb core那边自然就知道该怎么处理了.闲话少说,先来看struct usb_sg_request结构体.她来自include/linux/usb.h:
988 /**
989 * struct usb_sg_request - support for scatter/gather I/O
990 * @status: zero indicates success, else negative errno
991 * @bytes: counts bytes transferred.
992 *
993 * These requests are initialized using usb_sg_init(), and then are used
994 * as request handles passed to usb_sg_wait() or usb_sg_cancel(). Most
995 * members of the request object aren't for driver access.
996 *
997 * The status and bytecount values are valid only after usb_sg_wait()
998 * returns. If the status is zero, then the bytecount matches the total
999 * from the request.
1000 *
1001 * After an error completion, drivers may need to clear a halt condition
1002 * on the endpoint.
1003 */
1004 struct usb_sg_request {
1005 int status;
1006 size_t bytes;
1007
1008 /*
1009 * members below are private to usbcore,
1010 * and are not provided for driver access!
1011 */
1012 spinlock_t lock;
1013
1014 struct usb_device *dev;
1015 int pipe;
1016 struct scatterlist *sg;
1017 int nents;
1018
1019 int entries;
1020 struct urb **urbs;
1021
1022 int count;
1023 struct completion complete;
1024 };
整个usb系统都会使用这个数据结构,如果我们希望使用scatter gather方式的话.usb core已经为我们准备好了数据结构和相应的函数,我们只需要调用即可.一共有三个函数,她们是usb_sg_init,usb_sg_wait,usb_sg_cancel.我们要提交一个sg请求,需要做的是,先用usb_sg_init来初始化请求,然后usb_sg_wait()正式提交,然后我们该做的就都做了.如果想撤销一个sg请求,那么调用usb_sg_cancel即可.
咱们虽说不用仔细去看着三个函数内部是如何实现的,但至少得知道该传递什么参数吧.不妨来仔细看一下usb_sg_init()被调用时传递给她的参数.头一个刚才已经说了,就是sg request,第二个,需要告诉她是哪个usb设备要发送或接收数据,咱们给她传递的是us->pusb_dev,第三个,是哪个pipe,这个没什么好说的,pipe是上面一路传下来的.第四个参数,这是专门适用于中断传输的,被传输中断端点的轮询率,对于bulk传输,直接忽略,所以咱们传递了0.第五个和第六个参数就分别是sg数组和sg数组中元素的个数.然后第七个参数,length,传递的就是咱们希望传输的数据长度,最后一个是SLAB flag,内存申请相关的一个flag.如果驱动程序处于block I/O路径中应该使用GFP_NOIO,咱们这里SLAB_NOIO实际上是一个宏,实际上就是GFP_NOIO.不要问我为什么用SLAB_NOIO或者说GFP_NOIO,无可奉告.(如果你真的想知道为什么的话,回去看当初我们是如何调用usb_submit_urb()的,理由当时就已经讲过了.)这个函数成功返回值为0,否则返回负的错误码.初始化好了之后就可以为us->flags设置US_FLIDX_SG_ACTIVE了,对这个flag陌生吗?还是回去看usb_submit_urb(),当时我们也为urb设置了这么一个flag,US_FLDX_URB_ACTIVE,其实历史总是惊人的相似.当初我们对待urb的方式和如今对待sg request的方式几乎一样.所以其实是很好理解的.
对比一下当初调用usb_submit_urb()的代码,就会发现464到471这一段我们不会陌生,当年咱们提交urb之前就有这么一段,usb_stor_msg_common()函数中,只不过那时候是urb而不是sg,这两段代码之间何其的相似!只是年年岁岁花相似,岁岁年年人不同啊!然后474行,usb_sg_wait()函数得到调用.她所需要的参数就是sg request的地址,咱们传递了us->current_sg的地址给她.这个函数结束,US_FLIDX_SG_ACTIVE这个flag就可以clear掉了.返回值被保存在us->current_sg.status中,然后把她赋给了result.而us->current_sg.bytes保存了实际传输的长度,把她赋给*act_len,然后返回之前,once more,调用interpret_urb_result()转换一下结果.
最后,usb_stor_bulk_transfer_sg()函数返回之前还做了一件事,将剩下的长度赋值给了*residual.*residual是形参,实参是&srb->resid.而最终usb_stor_bulk_transfer_sg()返回的值就是interpret_urb_result()翻译过来的值.但是需要明白的一点是,这个函数的返回就意味着Bulk传输中的关键阶段,即数据阶段的结束.剩下一个阶段就是状态阶段了,要传递的是CSW,就像当初传递CBW一样.
回到usb_stor_Bulk_transport()函数中来,判断结果是否为USB_STOR_XFER_ERROR或者USB_STOR_XFER_LONG,前者表示出错,这没啥好说的.而后者表示设备试图发送的数据比咱们需要的数据要多,这种情况咱们使用一个fake sense data来向上层汇报,出错了,但是和一般的出错不一样的是,告诉上层,这个命令别再重发了.fake_sense刚开始初始化为0,这里设置为1,后面将会用到.到时候再看.目前只需要知道的是,这种情况并不是不存在,实际上usb mass storage bulk-only spec里边就定义了这种情况,spec说了对这种情况,下一个阶段还是要照样进行.至于设备干嘛要这样做,那就只有天知道了,就是说你明明只是对他说,”给我十块钱”,他却硬塞给你一百块钱.(我只是打个比方,别做梦了.)文雅一点说,这叫,原想采撷一枚红叶,你却给了我整个的枫林.
最后,解释一点,USB_STOR_XFER_LONG只是我们自己定义的一个宏,实际上是由interpret_urb_result()翻译过来的,真正的从usb core那一层传递过来的结果是叫做-EOVERFLOW,这一点在interpret_urb_result函数中能找到对应关系.-EOVERFLOW我们就常见了,顾名思义,就是溢出.
最后的最后,再解释一点,实际上usb core这一层做的最人性化的一点就是对urb和对sg的处理了.写代码的人喜欢把数据传输具体化为request,urb和sg都被化作request,即请求.而usb core的能耐就是让你写设备驱动的人能够只要申请一个请求,调用usb core提供的函数进行初始化,然后调用usb core提供的函数进行提交,这些步骤都是固定的,完全就像使用傻瓜照相机一样,然后进程可以睡眠,或者可以干别的事情,完事之后usb core会通知你.然后你就可以接下来干别的事情了.我做一个比方,就好比你考四六级,找了一个枪手,让他去给你考,你只要告诉他你的基本信息,把你的准考证给他,然后你就不用管别的什么了,剩下的事情他会去处理,然后你也不用担心完事之后他不会通知你,这简直是不容置疑的,因为你还没给钱呢.明白了不,小朋友?
相关推荐
根据给定的信息,“Linux那些事儿之我是U盘”这一标题及描述主要聚焦于USB技术在Linux环境下的工作原理和技术细节。接下来,我们将基于这个主题展开深入探讨,涵盖USB技术的基本概念、USB在Linux系统中的实现机制...
Linux那些事儿之我是U盘 Linux那些事儿之我是Hub Linux那些事儿之我是USB Core Linux那些事儿之我是UHCI Linux那些事儿之我是EHCI控制器 Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是...
### Linux那些事儿之我是USB(第2版)关键知识点概览 #### 一、书籍概述 - **核心主题**:本书主要围绕Linux内核中的USB子系统展开,深入剖析其工作原理和技术细节。 - **目标读者**:面向Linux初学者、驱动开发者...
读过《linux那些事儿之我是U盘》的人,都知道其风格,我就不多说了。 导读: linux那些事儿之我是U盘 linux那些事儿之我是HUB linux那些事儿之我是USB Core linux那些事儿之我是UHCI Linux那些事儿之我是EHCI主机控制...
本压缩包文件"linux那些事儿之我是USB.zip"包含了深入理解Linux USB驱动及内核相关知识的九个文档,包括Block层、EHCI主机控制器、HUB、PCI、SCSI硬盘、Sysfs、UHCI、USB core以及U盘。这些文档旨在提供一个系统性的...
3. **Linux那些事儿之我是U盘.pdf**: USB闪存驱动器,通常称为U盘,是常见的便携式存储设备。这部分可能讲述Linux如何识别、挂载和管理U盘,包括使用ums(USB Mass Storage)驱动程序,以及如何处理文件系统的读写...
导读.doc Linux那些事儿之我是Block层.pdf Linux那些事儿之我是EHCI主机控制器.pdf Linux那些事儿之我是Hub.pdf Linux那些事儿之我是USB_core.pdf Linux那些事儿之我是U盘.pdf等等 Linux那些事儿系列全在这里了
### Linux与USB存储设备——《Linux那些事儿之我是U盘》知识点提炼 #### 引言 本文基于一篇幽默且深入的教程《Linux那些事儿之我是U盘》,该文章通过作者的亲身经历和深入浅出的讲解,介绍了Linux操作系统中USB存储...
》包括《Linux那些事儿之我是Hub》、《Linux那些事儿之我是Sysfs》《Linux那些事儿之我是UHCI》、《Linux那些事儿之我是USB core》、《Linux那些事儿之我是U盘》,令人叹为观止的一个linux系列书籍。只能说,江山代...
“Linux那些事儿之我是U盘.pdf”将关注通用串行总线(USB)闪存驱动器。这部分会解释Linux如何识别和处理USB闪存设备,包括文件系统的挂载和数据交换过程。 “Linux那些事儿之我是USB Core.pdf”涉及Linux内核的USB...
Linux那些事儿之我是Block层 Linux那些事儿之我是EHCI主机控制器 Linux那些事儿之我是Hub Linux那些事儿之我是PCI Linux那些事儿之我是SCSI硬盘 Linux那些事儿之我是Sysfs ...Linux那些事儿之我是U盘
【Linux那些事儿之我是U盘1】这篇文章是一个关于Linux内核和USB设备驱动程序的系列教程,作者通过个人经历引入,讲述了自己如何接触并学习Linux技术。文章详细讲解了Linux内核中的USB总线、设备驱动和USB存储设备的...