usb u盘

  1.    
  小城故事-Makefile    
  
  
  
  
 kernel/drivers/usb/storage  
  
  
 这个目录里边的代码是针对一类设备的,不是某一种特定的设备,这一类设备就是USB Mass Storage 设备。关于这类设备,有专门的文档进行介绍,有相应的spec 描述这类设备的通信或者物理上电特性上等方面的规范,U 盘只是其中的一种,这种设备使用的通信协议被称为Bulk-Only Transport 协议。再比如,关于CONFIG_USB_STORAGE_SDDR55 这个选项,很显然这是SanDisk 的产品,并且是针对SM 卡的,这也不是U 盘,所以都不去理睬了。事实上,很容易确定,只有CONFIG_USB_STORAGE 这个选项是需要真正关心的,而它所对应的模块叫usb-storage.  
  
  
  2.    
  外面的世界很精彩    
  
  
 认真的思考一个问题:  
 我需要关注的仅仅是drivers/usb/storage/目录下面那相关的3000多行代码吗?就是这样几个文件就能让一个个不同的U盘在Linux下面工作起来吗?  
  
  
 问题远不是这样简单.外面的世界很精彩,作为U盘,她需要与usb core打交道,需要与scsi core打交道,需要与内存管理单元打交道,还有内核中许许多多其它模块打交道.外面的世界很大,远比我们想象的大.  
  
  
  
  
  
  
  usb core    
 实现一些核心的功能,为别的设备驱动程序提供服务(接口),比如申请内存,比如实现一些所有的设备都会需要的公共的函数.  
 drivers/usb/core  这个目录,就专门放一些核心的代码,比如初始化整个usb系统,初始化root hub,初始化host controller的代码  
  
  
 普通的设备要正常的工作,除了要有设备本身以外,还需要有一个控制器host controller,和这个控制器相连接在一起的叫root hub  
  
  
 现实中经常是让一个usb控制器和一个hub绑定在一起,专业一点说叫集成,而这个hub也被称作root hub,换言之,和usb控制器绑定在一起的hub就是系统中最根本的hub,其它的hub可以连接到她这里,然后可以延伸出去,外接别的设备,当然也可以不用别的hub,让usb设备直接接到root hub上.  
  
  
  
  
  
  
  usb host controller    
 控制所有的usb设备的通信.通常计算机的cpu并不是直接和usb设备打交道,而是和控制器打交道,他要对设备做什么,他会告诉控制器,而不是直接把指令发给设备,然后控制器再去负责处理这件事情,他会去指挥设备执行命令,而cpu就不用管剩下的事情,他还是该干嘛干嘛去,控制器替他去完成剩下的事情,事情办完了再通知cpu.否则让cpu去盯着每一个设备做每一件事情,那是不现实的  
  
  
 host controller单独的代码则移到host目录下面让负责各种host controller的人去维护  
 常见的host controller有三种,分别叫做EHCI,UHCI,OHCI  
  
  
  
  
  所以出来了三个概念:usb core,usb host,usb device    
  
  
  usb通信的灵魂就是usb协议. usb协议将是所有usb设备和usb主机所必须遵循的游戏规则.这种规则也很自然的体现在了代码中.于是,我们需要了解的不仅仅是drivers/usb/storage/目录下面的代码,还得去了解那外面的世界,虽然,只需要了解一点点.    
  
  
  
  
  
  
  3.    
  未曾开始却似结束    
  
  
 设备模型,但是不懂设备模型又怎能说自己懂设备驱动呢?读代码的人,写代码的人,都要知道, 什么是设备驱动?什么又是设备?设备和驱动之间究竟是什么关系? 设备如何与计算机主机联系起来?计算机世界里,设备有很多种类,比如PCI设备,比如ISA设备,再比如SCSI设备,再比如我们这里的USB设备.为设备联姻的是总线,是他把设备连入了计算机主机.但是与其说设备是嫁给了计算机主机,倒不如说设备是嫁给了设备驱动程序.很显然,在计算机世界里,无论风里雨里,陪伴着设备的正是驱动程序.  
  
  
  drivers/usb/storage/usb.c  
  
  
 module_usb_driver(usb_storage_driver);  
  
  
 #define module_usb_driver(__usb_driver) \  
     module_driver(__usb_driver, usb_register, \  
                 usb_deregister  
  
  
 usb_register.这个函数正是来自usb core.凡是usb设备驱动,都要调用这个函数来向usb core注册,从而让usb core知道有这么一个设备.  
  
  
 drivers/usb/core/hub.c  
 int  usb_hub_init (void)  
 {  
     if ( usb_register(&hub_driver)  < 0) {  
         printk(KERN_ERR "%s: can't register hub driver\n",  
             usbcore_name);  
         return -1;  
     }      
  
  
 }  
  
  
  
  
  4.    
  狂欢是一群人的孤单    
  
  
 Linux 设备模型中三个很重要的概念就是总线、设备和驱动,即 bus 、 device 和 driver 。  
 struct bus_type , struct device , struct device_driver ,这三个重要的数据结构都来自同一个地方,称 include/linux/device.h 。  
  
  
 总线有很多种,如 PCI 总线、 SCSI 总线、 USB 总线,所以我们会看到 Linux 内核代码中出现 pci_bus_type , scsi_bus_type , usb_bus_type,它们都是 struct bus_type 类型的变量。  
  
  
 struct bus_type 结构中两个非常重要的成员就是 struct kset drivers 和 struct kset devices  
 struct bus_type 与两个链表联系了起来,一个是 devices 的链表,一个是 drivers 的链表。也就是说,知道一条总线所对应的数据结构,就可以找到这条总线所关联的设备,及支持这类设备的驱动程序。  
  
  
  
  
 每次出现一个设备就要向总线汇报,或者说注册。每次出现一个驱动,也要向总线汇报,或者注册。比如系统初始化时,会扫描连接了哪些设备,并为每一个设备建立起一个 struct device 的变量,每一次有一个驱动程序,就要准备一个struct device_driver 结构的变量。把这些变量统统加入相应的链表,设备插入 devices 链表, 驱动插入 drivers 链表。 这样通过总线就能找到每一个设备,每一个驱动。  
  
  
  
  
  
  
  5.    
  总线,设备和驱动(上)    
  
  
 struct bus_type中为设备和驱动准备了两个链表,设备的结构体struct device中又有两个成员,struct bus_type *bus和struct device_driver *driver。驱动的结构体struct device_driver同样有两个成员,struct bus_type *bus和struct list_head devices;struct device和struct device_driver的定义和struct bus_type一样,在include/linux/device.h中。  
  
  
 struct device中的bus记录的是这个设备连在哪条总线上,driver记录的是这个设备用的是哪个驱动。  
 struct device_driver中的bus代表的也是这个驱动属于哪条总线,devices记录的是这个驱动支持的那些设备。devices(复数),而不是device(单数),因为一个驱动程序可以支持一个或多个设备,反过来一个设备则只会绑定给一个驱动程序。  
  
  
 一旦为一条总线申请了一个struct bus_type的数据结构之后,就往它的devices链表和drivers链表  
  
  
 每一个驱动本身去bus上面登记,或者说挂牌。具体到USB系统,每一个USB设备的驱动程序都会有一个struct usb_driver结构体  
 struct usb_driver {  
     const char *name;  
     int (*probe) (struct usb_interface *intf,  
               const struct usb_device_id *id);  
     void (*disconnect) (struct usb_interface *intf);  
     int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,  
             void *buf);  
     int (*suspend) (struct usb_interface *intf, pm_message_t message);  
     int (*resume) (struct usb_interface *intf);  
     int (*reset_resume)(struct usb_interface *intf);  
     int (*pre_reset)(struct usb_interface *intf);  
     int (*post_reset)(struct usb_interface *intf);  
     const struct usb_device_id *id_table;  
     struct usb_dynids dynids;  
      struct usbdrv_wrap drvwrap;    
     unsigned int no_dynamic_id:1;  
     unsigned int supports_autosuspend:1;  
     unsigned int disable_hub_initiated_lpm:1;  
     unsigned int soft_unbind:1;  
 };  
 #define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)  
  
  
 struct usbdrv_wrap {  
      struct device_driver driver;    
     int for_devices;  
 };  
 struct device_driver driver这个成员,USB Core为每一个设备驱动准备了一个函数,让它把这个struct device_driver driver插入到usb_bus_type中的drivers链表中去。这个函数是usb_register。  
  
  
 usb_register()--->  
 int usb_register_driver(struct usb_driver *new_driver, struct module *owner,  
             const char *mod_name)  
 {  
     retval = driver_register( &new_driver->drvwrap.driver );   
 }  
  
  
 drivers/usb/core/hub.c  
 static struct usb_driver hub_driver = {  
     .name =     "hub",  
     .probe =    hub_probe,  
     .disconnect =   hub_disconnect,  
     .suspend =  hub_suspend,  
     .resume =   hub_resume,  
     .reset_resume = hub_reset_resume,  
     .pre_reset =    hub_pre_reset,  
     .post_reset =   hub_post_reset,  
     .unlocked_ioctl = hub_ioctl,  
     .id_table = hub_id_table,  
     .supports_autosuspend = 1,   
 }  
  
  
 drivers/usb/core/devio.c  
 struct usb_driver usbfs_driver = {  
     .name =     "usbfs",  
     .probe =    driver_probe,  
     .disconnect =   driver_disconnect,  
     .suspend =  driver_suspend,  
     .resume =   driver_resume,  
 };  
  
  
 drivers/usb/storage/usb.c  
 static struct usb_driver usb_storage_driver = {  
     .name =     "usb-storage",  
     .probe =    storage_probe,  
     .disconnect =   usb_stor_disconnect,  
     .suspend =  usb_stor_suspend,  
     .resume =   usb_stor_resume,  
     .reset_resume = usb_stor_reset_resume,  
     .pre_reset =    usb_stor_pre_reset,  
     .post_reset =   usb_stor_post_reset,  
     .id_table = usb_storage_usb_ids,  
     .supports_autosuspend = 1,   
     .soft_unbind =  1,  
 };  
  
  
  
  
  
  
  
  
  6.    
  总线,设备和驱动(下)    
  
  
 bus上的两张链表记录了每一个device和driver,那么device和driver这两者之间又是如何联系起来的呢?  
  
  
 很久很久以前,先有的是device,每一个要用的device在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,然后操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个struct device结构,并且挂入总线中的devices链表中来,然后每一个驱动程序开始初始化,开始注册其struct device_driver结构,然后它去总线的devices链表中去寻找(遍历),去寻找每一个还没有绑定driver的设备,即struct device中的struct device_driver指针仍为空的设备,然后它会去观察这种设备的特征,看是否是他所支持的设备,如果是,那么调用一个叫做device_bind_driver的函数,然后他们就结为了秦晋之好.换句话说,把struct device中的struct device_driver driver指向这个driver,而struct device_driver driver把struct device加入他的那张struct list_head devices链表中来.就这样,bus,device,和driver,这三者之间或者说他们中的两两之间,就给联系上了.  
  
  
 int device_bind_driver(struct device *dev)--->driver_bound()  
 static void driver_bound(struct device *dev)  
 {  
    klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);  
 }  
  
  
 device_bind_driver()将device与driver绑定。它调用了两个内部函数。  
 其中drivers_sysfs_add()负责创建sysfs中driver和device指向对方的软链接。还有一个与它相对的函数drivers_sysfs_remove()。  
 driver_bound()则实际将device加入驱动的设备链表。因为在调用device_bind_driver()之前就已经设置过dev->driver了,所以这样就将device和driver绑定了。  
  
  
 热插拔的出现:  
 device可以在计算机启动以后在插入或者拔出计算机了.很难再说是先有device还是先有driver了.因为都有可能.device可以在任何时刻出现,而driver也可以在任何时刻被加载,每当一个struct device诞生,它就会去bus的drivers链表中寻找自己的另一半,反之,每当一个一个struct device_driver诞生,它就去bus的devices链表中寻找它的那些设备.如果找到了合适的,调用device_bind_driver绑定好.如果找不到,没有关系,等待吧。  
  
  
  
  
  
  
  7.    
  我是谁的他    
  
  
 static struct usb_driver usb_storage_driver = {  
     .name =     "usb-storage",  
     . probe =    storage_probe,    
      .disconnect =   usb_stor_disconnect,    
     .suspend =  usb_stor_suspend,  
     .resume =   usb_stor_resume,  
     .reset_resume = usb_stor_reset_resume,  
     .pre_reset =    usb_stor_pre_reset,  
     .post_reset =   usb_stor_post_reset,  
      .id_table = usb_storage_usb_ids,    
     .supports_autosuspend = 1,   
     .soft_unbind =  1,  
 };  
  
  
 一个device只能绑定一个driver,但driver并非只能支持一种设备,比如我有两块U盘,那么我可以一起都插入,但是我只需要加载一个模块,usb-storage,没听说过插入两块U盘就得加载两次驱动程序的,除非这两块U盘本身就得使用不同的驱动程序.也正是因为一个模块可以被多个设备共用,才会有模块计数这么一个说法.  
  
  
 既然一个driver可以支持多个device,那么当发现一个device的时候,如何知道哪个driver才是她的Mr.Right呢?这就是id_table的用处,让每一个struct usb_driver准备一张表,里边注明该driver支持哪些设备.如果你这个设备属于这张表里的,绑定吧,如果不属于这张表里的,那么不好意思,您请便.哪凉快上哪去.  
  
  
 truct usb_driver  
 {  
 const struct usb_device_id *id_table;  
 }  
  
  
 实际上是一个指针,一个struct usb_device_id结构体的指针,当然赋了值以后就是代表一个数组名了,正如我们在定义struct usb_driver usb_storage_driver中所赋的值那样,.id_table = usb_storage_usb_ids。  
  
  
  
  
  8.    
  从协议中来到协议中去(上)    
  
  
 static int storage_probe(struct  usb_interface  *intf,const struct  usb_device_id  *id)  
 void usb_stor_disconnect(struct  usb_interface  *intf)  
  
  
 每一个设备对应一个struct device结构体变量,针对USB设备,开发人员们设计了一个叫做struct usb_device的结构体。  
  
  
 struct usb_device {  
       struct device dev;  //属于每个设备的struct device结构体变量。  
 }  
  
  
  
  
 看起来很复杂的一个数据结构,不过我们目前不需要去理解她的每一个成员,不过我们可以看到,其中有一个成员struct device dev,这就是前面说的那个属于每个设备的struct device结构体变量。  
  
  
 struct usb_device,后来要调用的一个函数,usb_buffer_alloc,它就需要这个参数。  
  
  
 比struct usb_device更重要的数据结构是:struct usb_interface。USB接口(Interface)。  
  
  
  
  
  9.    
  从协议中来到协议中去(下)    
  
  
 usb设备要遵循的就是usb协议. 不管是软件还是硬件,在设计的伊始,总是要参考usb协议.怎么设计硬件,如何编写软件,不看usb协议,谁也不可能凭空想象出来.  
  
  
 usb协议规定了,每个usb设备都得有些基本的元素,称为描述符,有四类描述符是任何一种usb设备都得有的.他们是,device descriptor,configuration descriptor,interface descriptor,endpoint descriptor.描述符里的冬冬是一个设备出厂的时候就被厂家给固化在设备里了.  
  
  
 关于这几种描述符,usb core在总线扫描那会就会去读取,会去获得里边的信息,其中,device描述符描述的是整个device.  
  
  
 对于usb设备驱动程序编写者来说,usb_interface和usb_endpoint更加重要.一个interface对应一个usb设备驱动程序.比如:一个usb设备,两种功能,一个键盘,上面带一个扬声器,两个接口,那这样肯定得要两个驱动程序,一个是键盘驱动程序,一个是音频流驱动程序.  
  
  
  
  
 struct  usb_interface   
     /* array of alternate settings for this interface,  
      * stored in no particular order */  
     struct usb_host_interface *altsetting;  
     struct usb_host_interface *cur_altsetting;  /* the currently                     * active alternate setting */  
     unsigned num_altsetting;    /* number of alternate settings */  
     /* If there is an interface association descriptor then it will list  
      * the associated interfaces */  
     struct usb_interface_assoc_descriptor *intf_assoc;  
     int minor;          /* minor number this interface is  
                      * bound to */  
     enum usb_interface_condition condition;     /* state of binding */  
     unsigned sysfs_files_created:1; /* the sysfs attributes exist */  
     unsigned ep_devs_created:1; /* endpoint "devices" exist */  
     unsigned unregistering:1;   /* unregistration is in progress */  
     unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */  
     unsigned needs_altsetting0:1;   /* switch to altsetting 0 is pending */  
     unsigned needs_binding:1;   /* needs delayed unbind/rebind */  
     unsigned reset_running:1;  
     unsigned resetting_device:1;    /* true: bandwidth alloc after reset */  
     struct device dev;      /* interface specific device info */  
     struct device *usb_dev;  
     atomic_t pm_usage_cnt;      /* usage counter for autosuspend */  
     struct work_struct reset_ws;    /* for resets in atomic context */  
 };  
 #define  to_usb_interface(d)  container_of(d, struct usb_interface, dev)   
  
  
 USB通信的最基本的形式就是通过endpoint端点,一个接口有一个或多个端点,而作为像U盘这样的存储设备吧,它至少有一个控制端点,两个bulk端点.  
  
  
 usb协议里规定了,usb设备有四种通信方式,分别是控制传输,中断传输,批量传输,等时传输.其中,等时传输显然是用于音频和视频一类的设备,这类设备期望能够有个比较稳定的数据流,比如你在网上QQ视频聊天,肯定希望每分钟传输的图像/声音速率是比较稳定的,usb-storage里边肯定不会用到等时传输.因为我们只管copy一个文件.  
  
  
 U盘使用的是一个叫做Bulk-Only的传输协议.使用这种协议的设备只有两种传输方式,一种是批量传输,另一种是控制传输,控制传输是任何一种usb设备都必须支持的,它专门用于传输一些控制信息.而bulk传输,它就是U盘的主要工作,读写数据.  
  
  
 和endpoint齐名的有一个叫做管道,endpoint就是通信的发送或者接收点,你要发送数据,那你只要把数据发送到正确的端点那里就可以了.之所以U盘有两个bulk端点,是因为端点也是有方向的,一个叫做Bulk in,一个叫做Bulk out,从usb主机到设备称为out,从设备到主机称为in.  
  
  
 而管道,实际上只是为了让我们能够找到端点,就相当于我们日常说的邮编地址,管道应该有两端吧.  
  
  
 管道的另一端应该是usb主机,即前面说的那个host,usb协议里边也是这么说的,协议里边说pipes代表着一种能力,在主机和设备上的端点之间移动数据,usb里边所有的数据传输都是有主机发起的.一切都是以主机为核心,usb core里边很多函数就是,为了让usb host能够正确的完成数据传输或者说传输调度  
  
  
 比如说我要从U盘里读一个文件,那我告诉usb host某个端点能有用吗?那个文件又不是存放在一个端点里边,它不该是存放在U盘里边吗?即数据本身并不是在端点里,但是看上去却觉得仿佛在端点里.这一切的谜团,让我们在storage_probe()函数里去慢慢解开吧.  
  
  
  
  
  10.    
  梦开始的地方    
  
  
 对于U盘驱动程序来说,它真正驱使U盘工作却是始于storage_probe()函数。USB Core为设备找到了适合它的驱动程序,或者为驱动程序找到了它所支持的设备。  
    
 U盘驱动则会调用函数storage_probe()去认识对方(usb_device),它是一个什么样的设备?这里调用了四个函数get_device_info,get_protocol,get_transport,get_pipes。整个U盘驱动这部大戏,由storage_probe开始,由storage_disconnect结束。  
  
  
 static int storage_probe(struct  usb_interface  *intf,const struct  usb_device_id  *id)  
 {  
     struct  us_data  *us; //比较重要的结构体  
 }  
  
  
  struct us_data {  
 }  
 Linux内核中每一个重要的数据结构都很复杂。我们会为每一个设备申请一个us_data,因为这个结构中边的东西我们之后一直会用得着的。structus_data *us,us即usb storage  
  
  
 /* Convert between us_data and the corresponding Scsi_Host */  
 static inline struct Scsi_Host *us_to_host(struct us_data *us) {  
     return container_of((void *) us, struct Scsi_Host, hostdata);  
 }  
 static inline struct us_data *host_to_us(struct Scsi_Host *host) {  
     return (struct us_data *) host->hostdata;  
 }  
  
  
  
  
 struct Scsi_Host {  
    struct scsi_host_template *hostt;  
   unsigned long hostdata[0]  /* Used for storage of host specific stuff */    
 }  
  
  
 struct scsi_host_template usb_stor_host_template  
  
  
 storage_probe{  
   usb_stor_probe1()  
   usb_stor_probe2()  
 }  
  
  
 int usb_stor_probe1(struct us_data **pus,struct usb_interface *intf,const struct usb_device_id *id, struct us_unusual_dev *unusual_dev)  
 {  
   host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us));  
  
  
 }  
  
  
 usb_stor_host_template,这个变量我们以后还会多次碰到。scsi_host_alloc 就是SCSI子系统提供的函数,它的作用就是申请一个SCSI Host相应的数据结构。而它的第一个参数&;usb_stor_host_template,其实这是一个struct scsi_host_template的结构体指针,之所以USB Mass Storage里面会涉及SCSI这一层,是因为我们事实上把一块U盘模拟成了一块SCSI设备,对于SCSI设备来说,要想正常工作,得有一个SCSI卡,或者说SCSI Host。而按照SCSI这一层的规矩,要想申请一个SCSI Host的结构体,我们就得提供一个struct scsi_host_template结构体,这其实从名字可以看出,是一个模版,SCSI那层把一切都封装好了,只要提交一个模版给它,它就能为你提供一个structScsi_Host结构体。  
  
  
 按照SCSI层的规矩,要想申请一个SCSI Host,并且让它工作,我们需要调用三个函数:  
 第一个是scsi_host_alloc()  
 第二个是scsi_add_host()  
 第三个是scsi_scan_host()。  static void  usb_stor_scan_dwork (struct work_struct *work)这个工作队列去调用它  
 这三个函数我们都会在接下来的代码里面看到。  
    
 scsi_host_alloc()一调用,就是给struct Scsi_Host 结构申请了空间, 而只有调用了scsi_add_host()之后,SCSI核心层才知道有这个Host的存在,然后只有scsi_scan_host()被调用了之后,真正的设备才被发现。  
  
  
 scsi_host_alloc()需要两个参数,第一个参数是structscsi_host_template 的指针(&usb_stor_host_template),而第二个参数实际上是被称为驱动自己的数据,我们传递sizeof(*us)。SCSI层非常友好地给咱们提供了一个接口,在struct Scsi_Host结构体被设计时就专门准备了一个unsigned long hostdata[0]来给别的设备驱动使用,这个hostdata的大小由我们来定,把sizeof(*us)传递给scsi_host_alloc()就意味着给us申请了内存。而今后如果我们需要从us得到相应的SCSI Host就可以使用内联函数us_to_host();而反过来要想从SCSI Host得到相应的us则可以使用内联函数host_to_us().  
  
  
  
  
  11.    
  冰冻三尺非一日之寒.    
  
  
 int usb_stor_probe1(struct us_data **pus,struct usb_interface *intf,const struct usb_device_id *id, struct us_unusual_dev *unusual_dev){  
        
       result =  associate_dev (us, intf);  
        result =  get_device_info (us, id, unusual_dev);  
 }  
  
  
  
  
 /* Associate our private data with the USB device */为usb设备分配分配私有数据内存  
 static int associate_dev(struct us_data *us, struct usb_interface *intf)  
 {  
     /* Fill in the device-related fields */  
     us->pusb_dev = interface_to_usbdev(intf);  
     us->pusb_intf = intf;  
     us->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;  
     usb_stor_dbg(us, "Vendor: 0x%04x, Product: 0x%04x, Revision: 0x%04x\n",  
              le16_to_cpu(us->pusb_dev->descriptor.idVendor),  
              le16_to_cpu(us->pusb_dev->descriptor.idProduct),  
              le16_to_cpu(us->pusb_dev->descriptor.bcdDevice));  
     usb_stor_dbg(us, "Interface Subclass: 0x%02x, Protocol: 0x%02x\n",  
              intf->cur_altsetting->desc.bInterfaceSubClass,  
              intf->cur_altsetting->desc.bInterfaceProtocol);  
  
  
     /* Store our private data in the interface */  
      usb_set_intfdata (intf, us);  //&intf->dev->driver_data=us 保存私有数据到interface  
  
  
     /* Allocate the control/setup and DMA-mapped buffers */  
     us->cr =  kmalloc (sizeof(*us->cr), GFP_KERNEL);  
     if (!us->cr)  
         return -ENOMEM;  
  
  
     us->iobuf =  usb_alloc_coherent( us->pusb_dev, US_IOBUF_SIZE,  
             GFP_KERNEL, &us->iobuf_dma); // 申请内存 us->cr和us->iobuf都是指针,指向两段内存空间  
     if (!us->iobuf) {  
         usb_stor_dbg(us, "I/O buffer allocation failed\n");  
         return -ENOMEM;  
     }      
     return 0;  
 }  
  
  
  
 //&us->iobuf_dma,dma传输.此前我们都没有赋过值,这个函数调用之后被赋上值的,是dma_addr_t类型的变量,这个数据类型是Linux内核中专门为dma传输而准备的.为了支持dma传输,usb_alloc_coherent不仅仅是申请了地址,并且建立了dma映射,iobuf_dma就是记录着cr和iobuf的dma地址.  
  
  
  
  
  
  
  
  
  
 struct  usb_interface   
      struct  usb_host_interface  *cur_altsetting; //设置  
 }  
  
  
 struct  usb_host_interface   
     struct usb_interface_descriptor desc;  
     int extralen;  
     unsigned char *extra;   /* Extra descriptors */   
     /* array of desc.bNumEndpoint endpoints associated with this  
      * interface setting.  these will be in no particular order.  
      */  
     struct usb_host_endpoint *endpoint;    
     char *string;       /* iInterface string, if present */  
 };   
  
  
 struct  usb_interface_descriptor   
     __u8  bLength;  
     __u8  bDescriptorType;  
     __u8  bInterfaceNumber; //bInterfaceNumber,一个设备可以有多个Interface,于是每一个Interface就有编号  
     __u8  bAlternateSetting;  
     __u8  bNumEndpoints;  
     __u8  bInterfaceClass;  
     __u8  bInterfaceSubClass;  
     __u8  bInterfaceProtocol;  
     __u8  iInterface;  
 } __attribute__ ((packed));   
 #define USB_DT_INTERFACE_SIZE       9  
  
  
 static inline void  usb_set_intfdata (struct usb_interface *intf, void *data)  
 {     
     dev_set_drvdata(&intf->dev, data);  
 }  
  
  
 void * dev_get_drvdata (const struct device *dev)  
 {     
     if (dev && dev->p)  
         return dev->p->driver_data;  
     return NULL;  
 }   
  
  
  
  
  12.   
  
  冬天来了,春天还会远吗(一)   
  
  
  
  
  
 在整个usb-storage模块的代码中,其最重要的工作在usb_stor_control_thread()的函数中。这个函数的调用是从usb_stor_acquire_resources()函数进入的。  
  
  
 int usb_stor_probe2(struct us_data *us)  
  
 {  
  
 result =  usb_stor_acquire_resources (us);----> th = kthread_run( usb_stor_control_thread , us, "usb-storage");   
  
  
 }  
  
  
  
  
  
  
  
 然而在此之前,有四个函数:get_device_info,get_transport,get_protocol,get_pipes。这四个函数就是让驱动去认识设备的。驱动需要知道设备的名字,驱动需要知道设备是哪一种类型.  
  
  
  
  
 int usb_stor_probe1(struct us_data **pus,struct usb_interface *intf,const struct usb_device_id *id, struct us_unusual_dev *unusual_dev){  
  
        
  
       result =  associate_dev (us, intf);  
  
        result =  get_device_info (us, id, unusual_dev); //Get the unusual_devs entries and the descriptors 获得设备信息  
  
 }  
  
  
 /* Get the unusual_devs entries and the string descriptors */                                                     
 static int  get_device_info (struct us_data *us, const struct usb_device_id *id,struct us_unusual_dev *unusual_dev)       
  
 {  
  
 struct usb_interface_descriptor *idesc = &us->pusb_intf->cur_altsetting->desc;  //整个故事就是针对一个接口的,一个接口就对应一个接口描述符  
  
  
 }  
  
  
  
  
  
  
 struct us_unusual_dev {  
     const char* vendorName;  
     const char* productName;  
     __u8  useProtocol;  
     __u8  useTransport;  
     int (*initFunction)(struct us_data *);  
 };  
  
 struct  usb_device_id usb_storage_usb_ids[]  = {                                                                    
 #   include "unusual_devs.h"                                                                                      
     { }     /* Terminating entry */                                                                               
 };                                                                                                                
 MODULE_DEVICE_TABLE(usb, usb_storage_usb_ids);  
  
  
  
  
  
  
  
  
  
 //每一个USB_DEVICE_VER或者USB_INTERFACE_INFO就是构造一个struct usb_device_id的结构体变量,为其中的四个元素赋了值:match_flags、bInterfaceClass、bInterfaceSubClass和bInterfaceProtocol  
  
 #define  USB_DEVICE_INFO (cl, sc, pr) \  
     .match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, \  
     .bDeviceClass = (cl), \  
     .bDeviceSubClass = (sc), \  
     .bDeviceProtocol = (pr)  
  
 #define  USB_INTERFACE_INFO (cl, sc, pr) \  
     .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \  
     .bInterfaceClass = (cl), \  
     .bInterfaceSubClass = (sc), \  
     .bInterfaceProtocol = (pr)  
  
 struct  usb_device_id   
     /* which fields to match against? */  
     __u16        match_flags  
     /* Used for product specific matches; range is inclusive */   
     __u16       idVendor;  
     __u16       idProduct;  
     __u16       bcdDevice_lo;  
     __u16       bcdDevice_hi;  
     /* Used for device class matches */  
     __u8         bDeviceClass  
     __u8         bDeviceSubClass  
     __u8         bDeviceProtocol  
     /* Used for interface class matches */  
     __u8        bInterfaceClass;  
     __u8        bInterfaceSubClass;  
     __u8        bInterfaceProtocol;  
     /* Used for vendor-specific interface matches */  
     __u8        bInterfaceNumber;  
     /* not matched against */  
     kernel_ulong_t  driver_info  
         __attribute__((aligned(sizeof(kernel_ulong_t))));  
 };  
  
 (2)  
 USB规范或者说USB协议,把USB设备分成了很多类,然而每个类又分成子类。USB协议也是,首先每个接口属于一个Class,(为什么是把接口分类,而不把设备分类?在USB设备驱动中,因为每个设备驱动对应的是一种接口,而不是一种设备),然后Class下面分了SubClass,接着SubClass下面又按各种设备所遵循的不同的通信协议继续细分。  
  
 USB协议中为每一种Class、每一种SubClass和每一种Protocol定义一个数值,比如Mass Storage的Class就是0x08,USB_CLASS_MASS_STORAGE这个宏在include/linux/usb/ch9.h中定义,其值正是8。  
 #define USB_CLASS_MASS_STORAGE      8  
  
  
  
 USUAL_DEV(USB_SC_RBC, USB_PR_CB)  
  
  
 把这个宏展开,就是说定义了这么一个usb_device_id结构体变量,  
 match_flags=USB_DEVICE_ID_MATCH_INT_INFO  
 bInterfaceClass=USB_CLASS_MASS_STORAGE  
 bInterfaceSubClass=US_SC_RBC  
 bInterfaceProtocol=US_PR_CB  
  
 match_flag是给USB Core去用的,USB Core负责给设备寻找适合它的驱动,负责给驱动寻找适合它的设备,它所比较的就是struct usb_device_id的变量,而struct usb_device_id结构体中有许多成员,告诉USB Core,你只要比较bInterfaceClass,bInterfaceSubClass和bInterfaceProtocol即可。include/linux/mod_devicetable.h中针对struct usb_device_id中的每一个要比较的项定义了一个宏:  
  
  
 #define USB_DEVICE_ID_MATCH_VENDOR      0x0001                                                          
 #define USB_DEVICE_ID_MATCH_PRODUCT     0x0002                                                          
 #define USB_DEVICE_ID_MATCH_DEV_LO      0x0004                                                          
 #define USB_DEVICE_ID_MATCH_DEV_HI      0x0008                                                          
 #define USB_DEVICE_ID_MATCH_DEV_CLASS       0x0010                                                      
 #define USB_DEVICE_ID_MATCH_DEV_SUBCLASS    0x0020                                                      
 #define USB_DEVICE_ID_MATCH_DEV_PROTOCOL    0x0040                                                      
 #define USB_DEVICE_ID_MATCH_INT_CLASS       0x0080                                                      
 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS    0x0100                                                      
 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL    0x0200                                                      
 #define USB_DEVICE_ID_MATCH_INT_NUMBER      0x0400   
  
  
  
  13 .   
  冬天来了,春天还会远吗(二)     
  
 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \  
             vendorName, productName, useProtocol, useTransport, \  
             initFunction, flags) \  
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \  
   .driver_info = (flags) }  
  
  
 #define COMPLIANT_DEV   UNUSUAL_DEV  
  
  
 #define USUAL_DEV(useProto, useTrans) \  
 { USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, useProto, useTrans) }  
  
  
 /* Define the device is matched with Vendor ID and interface descriptors */  
 #define UNUSUAL_VENDOR_INTF(id_vendor, cl, sc, pr, \  
             vendorName, productName, useProtocol, useTransport, \  
             initFunction, flags) \  
 { \  
     .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \  
                 | USB_DEVICE_ID_MATCH_VENDOR, \  
     .idVendor    = (id_vendor), \  
     .bInterfaceClass = (cl), \  
     .bInterfaceSubClass = (sc), \  
     .bInterfaceProtocol = (pr), \  
     .driver_info = (flags) \  
 }  
  
  
 #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \  
             vendorName, productName, useProtocol, useTransport, \  
             initFunction, flags) \  
 {                   \  
     .vid    = id_vendor,        \  
     .pid    = id_product,       \  
     .bcdmin = bcdDeviceMin,     \  
     .bcdmax = bcdDeviceMax,     \  
 } 
 drivers/usb/storage/unusual_devs.h的作用,那么要做的是很显然的一件事情,如果一个厂家推出了一个新的设备,它有一些新的特征,而目前的设备驱动不足以完全支持它,那么厂家首先需要做的事情就是在unusual_devs.h中添加一个UNUSUAL_DEV来定义自己的设备,然后再看是否需要给内核打补丁以及如何打因此这几年unusual_devs.h这个文件的长度也是慢慢在增长。  
  
  14 .   冬天来了,春天还会远吗(三)     
usb_stor_probe1()--->  
static int get_device_info(struct us_data *us, const struct usb_device_id *id,struct us_unusual_dev *unusual_dev) 
{ 
     us->unusual_dev = unusual_dev; //把unusual_dev给记录在us里面,us里面也有这么一个成员 
    us->subclass = (unusual_dev->useProtocol == USB_SC_DEVICE) ? 
            idesc->bInterfaceSubClass : 
            unusual_dev->useProtocol; 
    us->protocol = (unusual_dev->useTransport == USB_PR_DEVICE) ? 
            idesc->bInterfaceProtocol : 
            unusual_dev->useTransport; 
    us->fflags = id->driver_info; 
//给us的另外三个成员赋值,subclass、protocol和flags。比如我们的U盘,它属于主流设备,在us_unusual_dev_list列表中能找到它,其subclass是US_SC_SCSI,而protocol是Bulk-only,即这里用宏US_PR_BULK代表。 
 
get_device_info这个函数就结束了它的使命。在USB Storage这部戏里,它将不再出场。  
  15.   冬天来了,春天还会远吗(四) 
结束了get_device_info,我们继续沿着storage_probe一步一步地走下去。继续,这就是我们前面提到过的三个函数,get_transport、get_protocol和get_pipes。一旦结束了这三个函数,我们就将进入本故事的高潮部分。 
 usb_stor_probe1() 
{ 
        /* Get standard transport and protocol settings */                         
    get_transport(us);                                                         
    get_protocol(us);  
 
 static void  get_transport (struct us_data *us) 
{ 
     case USB_PR_BULK:                                                          
        us->transport_name = "Bulk"; 
        us->transport =  usb_stor_Bulk_transport; 
        us->transport_reset =  usb_stor_Bulk_reset; 
        break; 
  //us的transport_name被赋值为“Bulk” 
transport被赋值为usb_stor_Bulk_transport 
transport_reset被赋值为usb_stor_Bulk_reset。其中我们最需要记住us的成员transport和transport_reset是两个函数指针。这两个函数叫“钩子”函数。这两个赋值我们需要牢记,日后我们一定会用到它们,因为这正是我们真正的数据传输时调用的东西。 
 
  
16.   冬天来了,春天还会远吗(五)   
 看完了get_transport()继续看get_protocol()和get_pipes().  
  usb_stor_probe1 () 
{ 
        /* Get standard transport and protocol settings */                         
    get_transport(us);                                                         
    get_protocol(us);  
 
static void  get_protocol (struct us_data *us)  
{ 
    case USB_SC_SCSI: 
        us->protocol_name = "Transparent SCSI"; 
        us->proto_handler = usb_stor_transparent_scsi_command; 
        break; 
//根据us->subclass来判断.对于U盘来说,spec里边规定了,subclass是US_SC_SCSI,所以这里就是两句赋值语句.一个是令us的protocol_name为"Transparent SCSI",另一个是令us的proto_handler为usb_stor_transparent_scsi_command.后者又是一个函数指针,我们日后遇到这个函数。 
 
int  usb_stor_probe2 (struct us_data *us) 
{ 
  result =  get_pipes (us); 
} 
static int  get_pipes (struct us_data *us) 
{ 
     struct usb_endpoint_descriptor *ep; 
    struct usb_endpoint_descriptor *ep_in = NULL; 
    struct usb_endpoint_descriptor *ep_out = NULL; 
    struct usb_endpoint_descriptor *ep_int = NULL; 
struct usb_host_interface *altsetting = us->pusb_intf->cur_altsetting; 
//us->pusb_intf,在associate_dev中赋得值,故事中最开始提到interface(指针).而它的成员cur_altsetting,就是当前的setting,或者说设置.在讲associate_dev的时候也已经遇到过,是一个struct usb_host_interface的结构体指针.现在这里用另一个指针临时代替一下, altsetting.接下来会用到它的成员,desc和endpoint. 
 for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { 
          ep = &altsetting->endpoint[i].desc; 
//altsetting->endpoint[i].desc,对照struct usb_host_endpoint这个结构体的定义,可知,desc正是一个struct usb_endpoint_descriptor的变量.刚刚定义了四个这种结构体的指针,ep,ep_in,ep_out,ep_int,就是用来记录端点描述符的,ep_in用于bulk-in,ep_out用于bulk-out,ep_int用于记录中断端点(如果有的话).而ep,只是一个临时指针. 
if ( usb_endpoint_xfer_bulk (ep)) { 
            if ( usb_endpoint_dir_in (ep)) { 
                if (!ep_in) 
                    ep_in = ep; 
            } else { 
                if (!ep_out) 
                    ep_out = ep; 
            } 
        } 
        else if ( usb_endpoint_is_int_in (ep)) { 
            if (!ep_int) 
                ep_int = ep; 
        } 
 
struct  usb_host_interface  { 
    struct  usb_interface_descriptor  desc; 
    int extralen; 
    unsigned char *extra;   /* Extra descriptors */ 
    /* array of desc.bNumEndpoint endpoints associated with this 
     * interface setting.  these will be in no particular order. 
     */ 
    struct  usb_host_endpoint  *endpoint; 
    char *string;       /* iInterface string, if present */ 
}; 
struct  usb_host_endpoint  { 
    struct  usb_endpoint_descriptor       desc;                                  
    struct usb_ss_ep_comp_descriptor    ss_ep_comp;                            
    struct list_head        urb_list; 
    void                *hcpriv; 
    struct ep_device        *ep_dev;    /* For sysfs info */                   
    unsigned char *extra;   /* Extra descriptors */                            
    int extralen; 
    int enabled;     
};   
//struct usb_host_interface,可以看到,它这两个成员,struct usb_interface_descriptor desc,和struct usb_host_endpoint *endpoint.其中,desc是interface的接口描述符,而endpoint这个指针记录的是几个endpoint,它们以数组的形式被存储,而endpoint指向数组头.  
  
/* USB_DT_ENDPOINT: Endpoint descriptor */ 
struct  usb_endpoint_descriptor  { 
    __u8  bLength; 
    __u8  bDescriptorType;    
    __u8   bEndpointAddress ;                                                    
    __u8   bmAttributes ; 
    __le16 wMaxPacketSize;   
    __u8  bInterval;     
    /* NOTE:  these two are _only_ in audio endpoints. */ 
    /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */ 
    __u8  bRefresh; 
    __u8  bSynchAddress; 
} __attribute__ ((packed));  
#define USB_DT_ENDPOINT_SIZE        7 
#define USB_DT_ENDPOINT_AUDIO_SIZE  9   /* Audio extension */ 
Flash memory---Flash是用来给用户存储数据的,而U盘中的Flash就相当于PC机中的硬盘,存储数据主要就靠它.那么除了给用户存储数据以外,设备自己还需要存储一些设备本身固有的东西,比如设备姓甚名谁?谁生产的?还有一些信息,比如该设备有几种配置,有几个接口,等等许多特性. 
除了Flash memory外,还有一个做EEPROM,也是用来存储的, 而Flash是基于EEPROM技术发展起来的一种低成本的ROM产品. EEPROM和Flash相同,都是需要电擦除,但EEPROM可以按字节擦除,而不向Flash那样一次擦除一个block. 
通常,USB设备里边,会有一个Flash芯片,会有一个EEPROM芯片,Flash给客户存储数据,而EEPROM用来存储设备本身的信息. 
usb spec规定的,这种格式就是一个个的描述符的格式.设备描述符,配置描述符,接口描述符,端点描述符,以及其它一些某一些类别的设备特有的描述符,比如hub描述符.这些东西都是很规范的,尤其对于这四种标准的描述符,每个usb设备都是规规矩矩的支持的,所以usb core层可以用一段相同的代码把它们都给读出来,而不用再让我们设备驱动程序去自己读了。 
/* USB_DT_INTERFACE: Interface descriptor */ 
struct  usb_interface_descriptor  { 
    __u8  bLength; 
    __u8  bDescriptorType; 
    __u8   bInterfaceNumber ; 
    __u8   bAlternateSetting ; 
    __u8   bNumEndpoints ; 
    __u8  bInterfaceClass; 
    __u8  bInterfaceSubClass; 
    __u8  bInterfaceProtocol; 
    __u8  iInterface; 
} __attribute__ ((packed)); 
#define USB_DT_INTERFACE_SIZE       9 
  
bNumEndpoints就是接口描述符中的成员,表示这个接口有多少个端点,不过这其中不包括0号端点,0号端点是任何一个usb设备都必须是提供的,这个端点专门用于进行控制传输,即它是一个控制端点. 
通常usb mass storage会有两个bulk端点,用于bulk传输,即所谓的批量传输.我们日常的读写U盘里的文件,就是属于批量传输,对于mass storage设备来说,bulk传输是它的主要工作方式,道理很简单,我们使用U盘就是用来读写文件的,谁没事天天去读它的这种描述符那种描述符呢,和这些描述符打交道无非就是为了帮助我们最终实现读写文件的工作,这才是每一个usb存储设备真正的使命.  
  
struct  usb_endpoint_descriptor  {                                                   
    __u8   bmAttributes ; 
} __attribute__ ((packed)); 
struct usb_endpoint_descriptor,它的成员中bmAttributes表示属性,总共8位,其中bit1和bit0共同称为Transfer Type, 
传输类型,即00表示控制,01表示等时,10表示批量,11表示中断. 
USB_ENDPOINT_XFERTYPE_MASK这个宏定义于include/linux/usb_ch9.h中: 
#define USB_ENDPOINT_XFERTYPE_MASK      0x03    /* in bmAttributes */ 
static inline int  usb_endpoint_xfer_bulk (const struct usb_endpoint_descriptor *epd) 
//判断端点传输类型  判断这个端点描述符描述的是不是一个Bulk端点 
{
    return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 
        USB_ENDPOINT_XFER_BULK); 
}    
  
struct  usb_endpoint_descriptor  {   
    __u8   bEndpointAddress ;                                                    
} __attribute__ ((packed));  
static inline int  usb_endpoint_dir_in (const struct usb_endpoint_descriptor *epd) 
{ 
    return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); 
} 
如果是Bulk端点,继续比较,struct usb_endpoint_descriptor中的一个成员bEndpointAddress,也是8个bit,或者说1个byte,其中bit7表示的是这个端点的方向,0表示OUT,1表示IN,OUT与IN是对主机而言.OUT就是从主机到设备,IN就是从设备到主机.而宏USB_DIR_IN仍然来自include/linux/usb_ch9.h 
#define USB_DIR_OUT         0       /* to device */ 
#define USB_DIR_IN          0x80        /* to host */ 
#define USB_ENDPOINT_DIR_MASK       0x80   bit7 
usb_endpoint_is_int_in - check if the endpoint is interrupt IN           
static inline int  usb_endpoint_is_int_in ( const struct usb_endpoint_descriptor *epd) 
{ 
    return usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd); 
}            
//为了让ep_in和ep_out指向该指的endpoint descriptor. 
如果这个端点是中断端点,那么就让ep_int指向它.每一类usb其上面有多少端点有何种端点都是不确定的,都得遵守该类设备的规范,而usb mass storage的规范说了,一个usb mass storage设备至少应该有两个bulk端点,除此之外,那个控制端点显然是必须的,另外,可能会有一个中断端点,这种设备支持CBI协议,Control/Bulk/Interrupt协议.我们也说过了,U盘遵守的是Bulk-only协议,它不需要有中断端点. 
总结: 
下一节我们将开始最精彩的部分,它就是伟大的usb_stor_acquire_resources(),我们小结一下,此前我们花了很大的篇幅来为 usb_stor_acquire_resources() 做铺垫,那我们来回顾一下,究竟做了哪些事情? 
首先我们从storage_probe出发,一共调用了五个函数,它们是 assocaite_dev,get_device_info,get_transport,get_protocol,get_pipes. 我们这样做的目的是什么?很简单,就是为了建立一个数据结构,它就是传说中的 struct us_data ,它的名字叫做us.我们把她建立了起来,为她申请了内存,为她的各个元素赋了值,目的就是为了让以后我们可以很好的利用她.这五个函数都不难,你一定也会写.难的是如何去定义struct us_data,别忘了这个数据结构是写代码的同志们专门为usb-storage模块而设计的. 
所谓编程,无非就是数据结构加上算法.   
  
17 
 通往春天的通道 
  
有管道都是用来传输东西的,只不过有些管道传输的是实实在在的物质,而有些管道传输的是数据。 
在USB代码中管道就是用来传输数据及通信。通信是双方的,不可能自言自语。而在USB的通信中,一方肯定是主机,另一方是什么?是设备吗?说得更确切一点,真正和主机进行通信的是设备内的端点。关于端点,我们也可以专业一点说,从硬件上来看它是实实在在存在的,它被实现为一种 FIFO ,支持多少个端点是接口芯片的一个重要指标。 
端点是主机和USB设备之间通信流的终点 。主机和设备可以进行不同种类的通信,或者说数据传输。首先,设备连接在USB总线上,USB总线为了分辨每一个设备,给每一个设备编上号,然后为了实现多种通信,设备方于是提供了端点,端点多了,自然也要编上号,而让主机最终和端点去联系。 
在USB的世界里,有四种管道,它们对应USB世界中的四种传输方式: 
控制传输对应控制管道、中断传输对应中断管道、批量传输对应批量管道及等时传输对应等时管道。每一个USB世界中的设备要在USB世界里生存,就得有它生存的管道。而管道的出现,正是为了让我们分辨端点,或者说连接端点。“ 主机与端点之间的数据链接就称为管道 。”  
  
在USB里面,知道设备号和端点号,知道了这两个号,主机就可以和设备通信,而USB主机就能知道和它通信的是哪个端点。 
而管道除了包含着两个号以外,通信的方向,管道里还包含了管道的类型,同样管道也如此,因为USB设备的端点有不同的类型,所以管道里就包含了一个字段来记录这一点。  
int  usb_stor_probe2 (struct us_data *us)--->  
static int  get_pipes (struct us_data *us)  
{ 
      /* Calculate and store the pipe values */                                  
    us->send_ctrl_pipe =  usb_sndctrlpipe (us->pusb_dev, 0);                     
    us->recv_ctrl_pipe =  usb_rcvctrlpipe (us->pusb_dev, 0);                   
//给us的控制输入和控制输出管道赋了值,管道是单向的。但是控制端点。控制端点是双向的,而USB规范规定了,每一个USB设备至少得有一个控制端点,其端点号为0。其他端点有没有得看具体设备而定,但这个端点是不管是什么设备,传递的endpoint变量值为0。显然其构造的两个管道就是对应这个0号控制端点的。 
  
    us->send_bulk_pipe =  usb_sndbulkpipe (us->pusb_dev,                         
        usb_endpoint_num(ep_out));                                             
    us->recv_bulk_pipe =  usb_rcvbulkpipe (us->pusb_dev, 
         usb_endpoint_num (ep_in));//获得端点号 
    if (ep_int) { 
        us->recv_intr_pipe =  usb_rcvintpipe (us->pusb_dev, 
             usb_endpoint_num (ep_int)); 
        us->ep_bInterval = ep_int->bInterval;  //对于中断端点,还得使用端点描述符中的bInterval字段,表示端点的中断请求间隔时间。 
    } 
} 
  
static inline unsigned int  __create_pipe (struct usb_device *dev, unsigned int endpoint)              {        
    return (dev->devnum << 8) | (endpoint << 15);                              
} 
  
//__create_pipe是一个宏,由上面的定义可以看出它为 构造一个宏提供了设备号和端点号 。在内核中使用一个unsigned int类型的变量来表征一个管道,其中8位~14位是设备号,即devnum,15位~18位是端点号,即endpoint。而咱们还看到有这么一个宏,USB_DIR_IN,是用来在管道里面标志数据传输方向的,一个管道要么只能输入,要么只能输出。        
  
             
/* Create various pipes... */                                                  
#define  usb_sndctrlpipe (dev, endpoint)  \                                      
    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint))                      
#define  usb_rcvctrlpipe (dev, endpoint)  \                                      
    ((PIPE_CONTROL << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) 
#define  usb_sndisocpipe (dev, endpoint)  \ 
    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint))                  
#define usb_rcvisocpipe(dev, endpoint)  \                                      
    ((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)     
#define usb_sndbulkpipe(dev, endpoint)  \ 
    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint))  
#define usb_rcvbulkpipe(dev, endpoint)  \ 
    ((PIPE_BULK << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)            
#define usb_sndintpipe(dev, endpoint)   \                                      
    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint)) 
#define usb_rcvintpipe(dev, endpoint)   \ 
    ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN) 
#define PIPE_CONTROL            2 
在管道里面,第7位(bit 7)是表示方向的。所以这里0x80也就是说设bit 7为1,这就表示 传输方向是由设备向主机的,也就是IN;而如果这一位是0,就表示 传输方向是由主机向设备的,也就是OUT。而正是因为USB_DIR_OUT是0,而USB_DIR_IN是1,所以我们看到定义管道时只有用到了USB_DIR_IN,而没有用到USB_DIR_OUT。
#define PIPE_ISOCHRONOUS        0                                                                                
#define PIPE_INTERRUPT          1                                                                                
#define PIPE_CONTROL            2                                                                                
#define PIPE_BULK    
USB有四种传输方式,即等时传输、中断传输、控制传输和批量传输。一个设备能支持这四种传输中的哪一种或者哪几种是设备本身的属性,在硬件设计时就确定了。比如一个纯粹的U盘,它肯定是支持批量传输和控制传输的。
不同的传输要求有不同的端点,所以对于U盘来说,它一定会有批量端点和控制端点,于是就得使用相应的管道来跟不同的端点联系。PIPE_ISOCHRONOUS就是标志等时通道,PIPE_INTERRUPT就是中断通道,PIPE_CONTROL就是控制通道,PIPE_BULK就是批量通道
static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
    return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
//对于批量端点和中断端点,在它们的端点描述符里有一个字段bEndpointAddress,这个字段共八位,但是它包含挺多信息的,比如这个端点是输入端点还是输出端点,比如这个端点的地址(总线枚举时给它分配的),以及这个端点的端点号。不过要取得它的端点号得用一个掩码USB_ENDPOINT_NUMBER_MASK,让bEndpointAddress和USB_ENDPOINT_NUMBER_MASK相与就能得到它的端点号。
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us) 
{
    int p;
    struct task_struct *th; 
    us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!us->current_urb) {
        usb_stor_dbg(us, "URB allocation failed\n");
        return -ENOMEM;
    }    
    /* Just before we start our control thread, initialize
     * the device if it needs initialization */
    if (us->unusual_dev->initFunction) {
        p = us->unusual_dev->initFunction(us);
        if (p)
            return p;
    }
    /* Start up our control thread */
    th =  kthread_run(usb_stor_control_thread, us, "usb-storage");
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    us->ctl_thread = th;
    return 0;
}
18. 
传说中的urb 
“urb”,全称USB Request Block。USB设备需要通信,要传递数据,就需要使用urb,确切地说,应该是USB设备驱动程序使用urb。实际上,作为USB设备驱动,它本身并不能直接操纵数据的传输,在USB这个大观园里,外接设备永远都是配角,真正的核心只是USB Core,而真正负责调度的是USB主机控制。这个通常看不见的USB主机控制器芯片,俨然是USB大观园中的大管家。设备驱动要发送信息,所需要做的是建立一个urb数据结构,并把这个数据结构交给核心层,而核心层会为所有设备统一完成调度,而设备在提交了urb之后需要做的,只是等待
/* Initialize all the dynamic resources we need */
static int  usb_stor_acquire_resources(struct us_data *us) 
{
    int p;
    struct task_struct *th; 
     us->current_urb = usb_alloc_urb(0, GFP_KERNEL); 
  
//等号左边us->current_urb,等号右边usb_alloc_urb()函数被调用。如果说struct us_data是usb mass storage中的主角,那么struct urb将毫无争议地成为整个USB子系统中的主角
    if (!us->current_urb) {
        usb_stor_dbg(us, "URB allocation failed\n");
        return -ENOMEM;
    }    
    /* Just before we start our control thread, initialize
     * the device if it needs initialization */
    if (us->unusual_dev->initFunction) {
        p = us->unusual_dev-> initFunction(us);
        if (p)
            return p;
    }
//有些设备需要一些初始化函数,它就定义在unusual_devs.h文件中,而我们通过UNUSUAL_DEV的定义已经把这些初始化函数赋给了us->unusual_dev的initFunction指针了。
    /* Start up our control thread */
     th = kthread_run(usb_stor_control_thread, us, "usb-storage"); 
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    us->ctl_thread = th;
    return 0;
}
struct urb {
    /* private: usb core and host controller only fields in the urb */
    struct kref kref;       /* reference count of the URB */
    void *hcpriv;           /* private data for host controller */
    atomic_t use_count;     /* concurrent submissions counter */
    atomic_t reject;        /* submissions will fail */
    int unlinked;           /* unlink error code */                                                                                                          
    /* public: documented fields in the urb that can be used by drivers */                                       
    struct list_head urb_list;  /* list head for use by the urb's                                                
                     * current owner */                                                                          
    struct list_head anchor_list;   /* the URB may be anchored */                                                
    struct usb_anchor *anchor;                                                                                   
    struct usb_device *dev;     /* (in) pointer to associated device */                                          
    struct usb_host_endpoint *ep;   /* (internal) pointer to endpoint */                                         
    unsigned int pipe;      /* (in) pipe information */                                                          
    unsigned int stream_id;     /* (in) stream ID */                                                             
    int status;         /* (return) non-ISO status */                                                            
    unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/                                             
    void *transfer_buffer;      /* (in) associated data buffer */                                                
    dma_addr_t transfer_dma;    /* (in) dma addr for transfer_buffer */                                          
    struct scatterlist *sg;     /* (in) scatter gather buffer list */                                            
    int num_mapped_sgs;     /* (internal) mapped sg entries */                                                   
    int num_sgs;            /* (in) number of entries in the sg list */                                          
    u32 transfer_buffer_length; /* (in) data buffer length */                                                    
    u32 actual_length;      /* (return) actual transfer length */                                                
    unsigned char *setup_packet;    /* (in) setup packet (control only) */                                       
    dma_addr_t setup_dma;       /* (in) dma addr for setup_packet */                                             
    int start_frame;        /* (modify) start frame (ISO) */
    int number_of_packets;      /* (in) number of ISO packets */
    int interval;           /* (modify) transfer interval
                     * (INT/ISO) */
    int error_count;        /* (return) number of ISO errors */
    void *context;          /* (in) context for completion */
    usb_complete_t complete;    /* (in) completion routine */
    struct usb_iso_packet_descriptor iso_frame_desc[0];
                    /* (in) ISO ONLY */
};
一个urb包含了执行USB传输所需要的所有信息。而作为驱动程序,要通信就必须创建这么一个数据结构,并且赋值,显然不同类型的传输,需要对urb赋不同的值,然后将她提交给底层,完了底层的USB Core会找到相应的USB主机控制器,从而具体实现数据的传输。传输完了之后,USB主机控制器会通知设备驱动程序。
调用usb_alloc_urb()申请了一个struct urb结构体。usb_alloc_urb()这个函数,它是USB Core所提供的一个函数,来自drivers/usb/core/urb.c,USB开发人员的确是给足了urb的面子,专门把和这个数据结构相关的代码整理在这么一个文件中了。
extern struct urb * usb_alloc_urb(intiso_packets, gfp_t mem_flags);
//为一个urb结构体申请内存。它有两个参数,其中第一个iso_packets用来在等时传输的方式下指定你需要传输多少个包,对于非等时模式来说,这个参数直接使用0。另一个参数mem_flags就是一个flag,表示申请内存的方式,这个flag将最终传递给kmalloc函数,我们这里传递的是GFP_KERNEL,usb_alloc_urb最终将返回一个urb指针,而us的成员current_urb也是一个struct urb的指针,所以就赋给它了。不过需要记住,usb_alloc_urb除了申请内存以外,还对结构体做了初始化,结构体urb被初始化为0,struct urb中还有一个引用计数,以及一个自旋锁,这些也同样被初始化了
那么设备和主机控制器的分工又是如何呢?在Linux中,设备驱动程序只要为每一次请求准备一个urb结构体变量,把它填充好(就是说赋上该赋的值),然后它调用USB Core提供的函数,把这个urb传递给主机控制器,主机控制器就会把各个设备驱动程序所提交的urb统一规划,去执行每一个操作。而这期间,USB设备驱动程序通常会进入睡眠,而一旦主机控制器把urb要做的事情给做完了,它会调用一个函数去唤醒USB设备驱动程序,然后USB设备驱动程序就可以继续往下走了。
19. 
彼岸花的传说(一) 
static int  usb_stor_acquire_resources(struct us_data *us)
{
th =  kthread_run(usb_stor_control_thread, us, "usb-storage");
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    us->ctl_thread = th;
}
#define  kthread_run(threadfn, data, namefmt, ...)              \
({                                     \
    struct task_struct *__k                        \
        =  kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
    if (!IS_ERR(__k))                          \
         wake_up_process(__k);                      \
    __k;                                   \
}) 
//kthread_create()执行后,就会有两个进程,一个是父进程,一个是子进程,子进程将会执行usb_stor_control_thread(),而us是作为usb_stor_control_thread函数的参数(实参),执行完usb_stor_control_thread()之后,子进程就结束了,它会调用exit()函数退出。而父进程继续顺着usb_stor_acquire_resources()函数往下走,kthread_create()函数对于父进程而言返回的是子进程的进程task_struct结构体指针,调用IS_ERR(th)判断返回的指针是否是错误代码,若是IS_ERR(th)为真,则调用PTR_ERR(th)读出实际的错误代码。
wake_up_process(th);唤醒子进程,之所以需要唤醒子进程,是因为当你用kthread_create()创建一个子进程之后,它并不会立即执行,它要等待你唤醒了之后才会执行。
19. 
彼岸花的传说(三) 
  
usb_stor_probe1
{
init_waitqueue_head( &us->delay_wait);
INIT_DELAYED_WORK(&us->scan_dwork,  usb_stor_scan_dwork);
}
usb_stor_probe2
{
queue_delayed_work(system_freezable_wq, &us-> scan_dwork,delay_use * HZ); 
}
static void  usb_stor_scan_dwork(struct work_struct *work) 
{
  if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) {                                      
        mutex_lock(&us->dev_mutex);                                                                             
        us->max_lun =  usb_stor_Bulk_max_lun(us);  //对于有多个LUN的设备,调用usb_stor_Bulk_max_lun()来获得max_lun。                                               mutex_unlock(&us->dev_mutex);                                                                           
    }
scsi_scan_host(us_to_host(us));  
//执行scsi_scan_host()函数扫描,扫描然后就知道这个host或者说这个SCSI卡上面接了什么设备(这个只是模拟的SCSI卡),然后cat/proc/scsi/scsi才能看到您的U盘。
}
  
static void  get_transport (struct us_data *us) 
{ 
     case USB_PR_BULK:                                                          
        us->transport_name = "Bulk"; 
        us->transport =  usb_stor_Bulk_transport; 
        us->transport_reset =  usb_stor_Bulk_reset; 
        break; 
  //us的transport_name被赋值为“Bulk” 
transport被赋值为usb_stor_Bulk_transport 
transport_reset被赋值为usb_stor_Bulk_reset。其中我们最需要记住us的成员transport和transport_reset是两个函数指针。这两个函数叫“钩子”函数。这两个赋值我们需要牢记,日后我们一定会用到它们,因为这正是我们真正的数据传输时调用的东西。 
 
int  usb_stor_Bulk_reset(struct us_data *us) 
{
    return  usb_stor_reset_common(us, US_BULK_RESET_REQUEST, 
                 USB_TYPE_CLASS | USB_RECIP_INTERFACE,
                 0, us->ifnum, NULL, 0);
}
EXPORT_SYMBOL_GPL(usb_stor_Bulk_reset);
static int  usb_stor_reset_common(struct us_data *us,
        u8 request, u8 requesttype,
        u16 value, u16 index, void *data, u16 size)
{
   wait_event_interruptible_timeout(us->delay_wait,
            test_bit(US_FLIDX_DISCONNECTING, &us->dflags),
            HZ*6);
}
//wait_event_interruptible_timeout()是一个宏,它代表着Linux中的一种等待机制,等待某个事件的发生,函数原型中,第1个参数是一个等待队列头,即wait_queue_head_t定义的变量,在内核中使用init_waitqueue_head()函数初始化这个等待队列,然后第3个参数是设置超时。比如这里设了5秒,这表示如果5秒到了,那么函数会返回0,不管其他条件如何。第2个参数是一种等待的条件,或者说等待的事件,如果条件满足了,那么函数也会返回,条件要是不满足,那么这个进程会进入睡眠,不过interruptible表明了信号可以把它中断。
 
一旦进入睡眠,那么有三种情况:一种是wake_up或者wake_up_interruptible函数被另一个进程执行,从而唤醒它,第二种是信号中断它,第三种就是刚才讲的超时,时间到了,自然就会返回。
先判断US_FLIDX_DISCONNECTING这个flag有没有设置,如果没有设置才进入睡眠。在进入睡眠之后,如果5秒之内没有把U盘拔出来,那么5秒一到,函数返回0,继续往下走,如果在5秒之前拔出来U盘了,那么后来咱们会讲,storage_disconnect()函数会执行,它会设置US_FLIDX_DISCONNECTING这个flag,并且它会调用wake_up(&;us->scsi_scan_wait)来唤醒这里睡眠的进程,这样函数就会提前返回,不用等到5秒再返回了。总之不管条件满不满足,5秒之内肯定会返回,所以我们继续往下看。
20. 
彼岸花的传说(四) 
  
U盘,不仅仅是USB设备,还是“盘”,它还需遵守USB Mass Storage协议,以及Transparent SCSI规范。从驱动程序的角度来看,它和一般的SCSI磁盘差不多。所以U盘的工作真正需要的是四个模块, usbcore,scsi_mod,sd_mod,以及咱们这里的usb-storage,其中sd_mod恰恰就是SCSI硬盘的驱动程序。没有它,你的SCSI硬盘就别想在Linux下面转起来。
usb_stor_control_thread(),当初用kthread_create创建它时,从此以后一个进程变成两个进程,沿着storage_probe讲完的是父进程,父进程最终返回了,而子进程则没有那么简单,usb_stor_control_thread()中的死循环注定了这个子进程是一个永恒的进程,只要这个模块还没有被卸载,或者说还没有被要求卸载,这个子进程就必将永垂不朽地战斗下去。
static int  usb_stor_acquire_resources(struct us_data *us)
{
th =  kthread_run(us b_stor_control_thread, us, "usb-storage");
    if (IS_ERR(th)) {
        dev_warn(&us->pusb_intf->dev,
                "Unable to start control thread\n");
        return PTR_ERR(th);
    }
    
SCSI核心层,硬件上来说,SCSI命令就是SCSI主机到SCSI设备,而从代码的角度来说,SCSI核心层要求为每一个SCSI主机实现一个queuecommand命令,每一次应用层发送
来了 SCSI命令了,比如你去读写/dev/sda,最终SCSI核心层就会调用与该主机相对应queuecommand,(确切地说是structScsi_Host结构体中的成员struct scsi_host_template中的成员指针queuecommand,这是一个函数指针。)那么我们来看,当初我们定义的struct scsi_host_template usb_stor_host_template,其中的确有一个queuecommand,我们赋给它的值也是queuecommand,即我们让queuecommand指向一个叫做queuecommand的函数
struct scsi_host_template  usb_stor_host_template = { 
.queuecommand =         queuecommand,
21. 
彼岸花的传说(五) 
  
static int  usb_stor_control_thread(void * __us)
{
    struct us_data *us = (struct us_data *)__us;
    struct Scsi_Host *host = us_to_host(us);
    for (;;) {
        usb_stor_dbg(us, "*** thread sleeping\n");
        if (wait_for_completion_interruptible(&us->cmnd_ready))
           break;
        usb_stor_dbg(us, "*** thread awakened\n");
        /* lock the device pointers */
        mutex_lock(&(us->dev_mutex));
        /* lock access to the state */
        scsi_lock(host);
        /* When we are called with no command pending, we're done */
        if (us->srb == NULL) {
            scsi_unlock(host);
            mutex_unlock(&us->dev_mutex);
            usb_stor_dbg(us, "-- exiting\n");
            break;
        }
        /* has the command timed out *already* ? */
        if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) { //判断flag,US_FLDX_TIMED_OUT这个flag的含义超时了。
            us->srb->result = DID_ABORT << 16;
            goto SkipForAbort;
        }
        scsi_unlock(host);
        /* reject the command if the direction indicator
         * is UNKNOWN
         */
        if (us->srb->sc_data_direction ==  DMA_BIDIRECTIONAL) { //这个宏表示数据阶段数据传输是双向,srb的sc_data_direction是DMA_BIDIRECTIONAL时,自然就当做出错了。因为不确定方向的话也就没法传输数据了。
            usb_stor_dbg(us, "UNKNOWN data direction\n");
            us->srb->result = DID_ERROR << 16;
        }
        /* reject if target != 0 or if LUN is higher than
         * the maximum known LUN
         */
        else if ( us->srb->device->id &&
                !(us->fflags &  US_FL_SCM_MULT_TARG)) {
            usb_stor_dbg(us, "Bad target number (%d:%d)\n",
                     us->srb->device->id, us->srb->device->lun);
            us->srb->result = DID_BAD_TARGET << 16;
       }
//US_FL_SCM_MULT_TARG这个flag,表示设备支持多个target,对于那些不支持多个target的设备,其us->srb->device->id必须为0。
struct us_data结构体中的成员struct scsi_cmnd * srb,struct scsi_cmnd结构体中有一成员struct scsi_device * device,描述一个SCSI设备,就像过去的struct usb_device用来描述USB设备一样。
        else if (us->srb->device->lun >  us->max_lun) {
            usb_stor_dbg(us, "Bad LUN (%d:%d)\n",
                     us->srb->device->id, us->srb->device->lun);
            us->srb->result = DID_BAD_TARGET << 16;
        }
//us->srb->device->lun不应该大于us->max_lun,us->max_lun早在usb_stor_scan_thread()中调用usb_stor_Bulk_max_lun()函数来向usb mass storage设备获得的最大LUN,比如MAX LUN等于3,那么这个设备支持的就是4个LUN,即0,1,2,3。而us->srb->device->lun则可以是这四个值中的任意一个,看传递进来的命令是要访问谁了。但它显然不可能超过MAX LUN。
        /* Handle those devices which need us to fake
         * their inquiry data */
        else if ( (us->srb->cmnd[0] == INQUIRY) && 
                (us->fflags & US_FL_FIX_INQUIRY)) {
            unsigned char data_ptr[36] = {
                0x00, 0x80, 0x02, 0x02,
                0x1F, 0x00, 0x00, 0x00};
            usb_stor_dbg(us, "Faking INQUIRY command\n");
    fill_inquiry_response(us, data_ptr, 36);
            us->srb->result = SAM_STAT_GOOD;
        }
//flag-US_FL_FIX_INQUIRY,这又是us->flags中众多flag中的一个,一些定义于drivers/usb/storage/unusal_devs.h中的设备有这个flag。事实上,通常大多数设备的厂商名(Vendor Name)和产品名(Product Name)是通过INQUIRY命令来获得的,而这个flag表明,这些设备的厂商名和产品名不需要查询,或者根本就不支持查询,它们的厂商名和产品名直接就定义好了,在unusal_devs.h中就设好了。
        /* we've got a command, let's do it! */
        else {
            US_DEBUG(usb_stor_show_command(us, us->srb));
            us->proto_handler(us->srb, us);
            usb_mark_last_busy(us->pusb_dev);
        }
        /* lock access to the state */
        scsi_lock(host);
        /* indicate that the command is done */
        if (us->srb->result != DID_ABORT << 16) {
            usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
                     us->srb->result);
            us->srb->scsi_done(us->srb);
        } else {
SkipForAbort:
            usb_stor_dbg(us, "scsi command aborted\n");
        }
        /* If an abort request was received we need to signal that
         * the abort has finished.  The proper test for this is
         * the TIMED_OUT flag, not srb->result == DID_ABORT, because
         * the timeout might have occurred after the command had
         * already completed with a different result code. */
        if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
            complete(&(us->notify));
            /* Allow USB transfers to resume */
           clear_bit(US_FLIDX_ABORTING, &us->dflags);
            clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
        }
        /* finished working on this command */
        us->srb = NULL;
        scsi_unlock(host);
        /* unlock the device pointers */
        mutex_unlock(&us->dev_mutex);
    } /* for (;;) */
    /* Wait until we are told to stop */
    for (;;) {
        set_current_state(TASK_INTERRUPTIBLE);
        if (kthread_should_stop())
            break;
        schedule();
    }
    __set_current_state(TASK_RUNNING);
    return 0;
}
}
enum dma_data_direction {
    DMA_BIDIRECTIONAL = 0, //DMA_BIDIRECTIONAL表示两个方向都有可能,不知道究竟是哪个方向
    DMA_TO_DEVICE = 1,
    DMA_FROM_DEVICE = 2,
    DMA_NONE = 3,
};
这些代码被用来表示数据阶段数据传输的方向。DMA_TO_DEVICE表示从主存到设备,DMA_FROM_DEVICE表示从设备到主存。DMA_NONE则只被用于调试,一般不能使用否则将有可能导致内核崩溃。USB Mass Storage协议中边规定了双向传输是非法的,而一个命令传输零数据是合法的,比如TEST_UNIT_READY命令就不用传输数据。
struct scsi_device {
unsigned int id, lun, channel; 
}
//unsigned int id,lun,channel这三个成员,定位一个SCSI设备必要的三个成员,一个SCSI卡所控制的设备被划分为几层,先是若干个channel,然后每个channel上有若干个target,每个target用一个target id来表示,然后一个target可以有若干个lun,判断的是target id。对于不支持多个target的设备,必须为0。对于绝大多数USB Mass Storage设备来说,它们的target id肯定为0。有些设备厂家就是要标新立异,它就是要让设备支持多个target,于是它就可以设置US_FL_SCM_MULT_TARG这么一个flag.
22. 
彼岸花的传说(六) 
  
INQUIRY命令是最基本的一个SCSI命令。比如主机第一次探测设备时就要用INQUIRY命令来了解这是一个什么设备,如果SCSI总线上有一个插槽插了一个设备,那么SCSI主机就问它,你是SCSI磁盘,还是SCSI磁带,又或是SCSI的CD ROM呢?作为设备,它内部一定有一段固件程序,即所谓的firmware。它就在接收到主机的INQUIRY命令之后做出回答。
依据SCSI协议中规定的格式了。不仅仅INQUIRY命令,具体来说, 设备在受到INQUIRY命令查询时,它的相应遵从SCSI协议中规定的标准格式,标准格式规定了,响应数据必须至少包含36个字节。所以252行,如果data_len小于36,就不往下走了,返回吧。
INQUIRY命令就是查询,查询设备的一些基本信息。从软件的角度来说,在主机扫描时,或者说枚举时,向每一个设备发送这个命令,并且获得回答,驱动程序从此就会保存这些信息,因为这些信息之后可能都会用到或者说其中的一部分会被用到。 sudo apt-get install sg3-utils 推荐的工具是sg_utils3,这是一个软件包,Linux中可以使用的软件包,到处都有,下了之后安装上,包含一个应用程序sg_inq,这其实就是给设备发送INQUIRY命令用的。
sg_inq /dev/sda 
standard INQUIRY:
  PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3]
  [AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=0  Resp_data_format=2
  SCCS=0  ACC=0  TPGS=0  3PC=0  Protect=0  [BQue=0]
  EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0
  [RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=0
  [SPI: Clocking=0x0  QAS=0  IUS=0]
    length=96 (0x60)   Peripheral device type: disk
 Vendor identification: ATA     
 Product identification: ST1000LM048-2E71
 Product revision level: SDM1
 Unit serial number:             WDECXGDB
使用sg_inq命令可以查询到关于这块U盘的基本信息。实际上sg_inq可以查询所有SCSI设备的信息,因为INQUIRY本来就是一个标准的SCSI命令。当然以上这些信息中,我们之后用得到的大概也就是Vendor ID,Product ID,Product revision,以及length,device type--disk。
void fill_inquiry_response(struct us_data *us, unsigned char *data,unsigned int data_len)
{
    if (data_len < 36) /* You lose. */ 响应数据必须至少包含36个字节
        return;
    memset(data+8, ' ', 28);
    if ( data[0]&0x20) { /* USB device currently not connected. Return
                  peripheral qualifier 001b ("...however, the
                  physical device is not currently connected
                  to this logical unit") and leave vendor and
                  product identification empty. ("If the target
                  does store some of the INQUIRY data on the
                  device, it may return zeros or ASCII spaces
                  (20h) in those fields until the data is
                  available from the device."). */
    } else {
         u16 bcdDevice = le16_to_cpu(us->pusb_dev->descriptor.bcdDevice); 
        int n;
        n = strlen(us->unusual_dev->vendorName);
        memcpy( data+8, us->unusual_dev->vendorName, min(8, n));
        n = strlen(us->unusual_dev->productName);
        memcpy( data+16, us->unusual_dev->productName, min(16, n));
//如果不是20h,比如传递进来的data[0]就是0,data[8]开始的8个字节可以保存厂商相关的信息,us->unusual_dev->vendorName,就是把其中的vendorName复制到data数组中来,但是如果vendorName超过8个字符了那可不行,只取前8个就行了。productName也是一样的方法,复制到data数组中来,协议中规定了,从16开始存放productName,不能超过16个字符,那么“Flash Disk”也没有问题。
        data[32] = 0x30 + ((bcdDevice>>12) & 0x0F);
        data[33] = 0x30 + ((bcdDevice>>8) & 0x0F);
        data[34] = 0x30 + ((bcdDevice>>4) & 0x0F);
        data[35] = 0x30 + ((bcdDevice) & 0x0F);
    }
//us->pusb_dev->descriptor.bcdDevice,struct us_data中有一个成员struct usb_device *pusb_dev,而struct usb_device中有一个成员struct usb_device_descriptordescriptor,而structusb_device_descriptor中的成员__u16 bcdDevice,表示制造商指定的产品的版本号,规定是用版本号,制造商id和产品id来标志一个设备。bcdDevice一共16位,是以bcd码的方式保存的信息,也就是说,每4位代表一个十进制的数,比如00110110 1001 0111就代表的3697。而在SCSI标准的INQUIRY data中,data[32]到data[35]被定义为保存这四个数,并且要求以ASCII码的方式保存。ASCII码中48对应咱们日常的0,49对应1,50对应2,也就是说得在现有数字的基础上加上48,或者说加上0x30。这就是290行到293行所表达的意思。
     usb_stor_set_xfer_buf(data, data_len, us->srb);
//一切准备好了之后,我们就可以把data数组,这个包含36个字符的信息发送到SCSI命令指定的位置了,即srb指定的位置。usb_stor_set_xfer_buf要干的工作。
}
判断data[0]是否是20h,SCSI协议中规定了,标准的INQUIRY data的data[0],总共有8个bit。其中bit7~bi5被称为peripheral qualifier(三位),而bit4~bit0被称为perpheral device type(五位),它们代表了不同的含义,但是20h就表示peripheral qualifier这个外围设备限定符为001b,而peripheral device type这个外围设备类型则为00h。查阅SCSI协议可知,后者代表的是设备类型为磁盘,或者说直接访问设备,前者代表的是目标设备的当前LUN支持这种类型。然而,实际的物理设备并没有连接在当前LUN上。在data[36]中,从data[8]一直到data[35]这28个字节保存的都是厂商和产品的信息。SCSI协议中写了,如果设备中保存这些信息,那么它可以暂时先返回0x20h,因为现在是系统poweron时期或者是reset期间,要尽量减少延时,于是fill_inquiry_response()就会把data[8]到data[35]都给设置成0。等到保存在设备上的这些信息可以读了再去读。
static int  usb_stor_control_thread(void * __us)
{
fill_inquiry_response(us,  data_ptr, 36);
//先解释一下之前定义data_ptr[36]时初始化的前8个元素。它们的含义都和scsi协议规定的对应。data_ptr[0]不用说了,data_ptr[1]被赋为0x80,这表明这个设备是可移除的,data_ptr[2]被赋为0x02这说明设备遵循SCSI-2协议,data_ptr[3]被赋为0x02,说明数据格式遵循国际标准化组织所规定的格式,而data_ptr[4]被称为additional length,附加参数的长度,即除了用这么一个标准格式的数据响应之外,可能还会返回更多的一些信息。这里设置的是0x1F。
}
23. 
彼岸花的传说(七) 
INQUIRY命令准备的数据保存到了我们自己定义的一个结构体中,即struct data_ptr[36],但是我们是为了回应一个SCSI命令,最终需要知道答案的是SCSI核心层。正是它们传递了一个scsi_cmnd结构体下来,即srb。struct scsi_cmnd中有两个成员,即unsigned request_bufflen和void *request_buffer,应该 把data数组中的数据传送到request_buffer中去,这样,SCSI核心层就知道去哪里获取结果。
/* Store the contents of buffer into srb's transfer buffer and set the                                                                  
 * SCSI residue.                                                                                                                        
 */                                                                                                                                     
void  usb_stor_set_xfer_buf(unsigned char *buffer,                                                                                       
    unsigned int buflen, struct scsi_cmnd *srb)                                                                                         
{                                                                                                                                       
    unsigned int offset = 0;                                                                                                            
    struct scatterlist *sg = NULL;                                                                                                      
                                                                                                                                        
    buflen = min(buflen, scsi_bufflen(srb));                                                                                            
    buflen =  usb_stor_access_xfer_buf(buffer, buflen, srb, &sg, &offset,                                                                
            TO_XFER_BUF);                                                                                                               
    if (buflen < scsi_bufflen(srb))                                                                                                     
        scsi_set_resid(srb, scsi_bufflen(srb) - buflen);                                                                                
scatter/gather,它是一种用于高性能IO的标准技术。它通常意味着一种DMA传输方式,对于一个给定的数据块,它可能在内存中存在于一些离散的缓冲区,就是一些不连续的内存缓冲区一起保存一个数据块。
/* Copy a buffer of length buflen to/from the srb's transfer buffer.
 * Update the **sgptr and *offset variables so that the next copy will
 * pick up from where this one left off.
 */
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,
    unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
    unsigned int *offset, enum xfer_buf_dir dir)
{
    unsigned int cnt;
    struct scatterlist *sg = *sgptr;
    /* We have to go through the list one entry
     * at a time.  Each s-g entry contains some number of pages, and
     * each page has to be kmap()'ed separately.  If the page is already
     * in kernel-addressable memory then kmap() will return its address.
     * If the page is not directly accessible -- such as a user buffer
     * located in high memory -- then kmap() will map it to a temporary
     * position in the kernel's virtual address space.
     */
    if (!sg)
        sg = scsi_sglist(srb);
    /* This loop handles a single s-g list entry, which may
     * include multiple pages.  Find the initial page structure
     * and the starting offset within the page, and update
     * the *offset and **sgptr values for the next loop.
     */
    cnt = 0;
    while (cnt < buflen && sg) {
        struct page *page = sg_page(sg) +
                ((sg->offset + *offset) >> PAGE_SHIFT);
        unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
        unsigned int sglen = sg->length - *offset;
        if (sglen > buflen - cnt) {
            /* Transfer ends within this s-g entry */
            sglen = buflen - cnt;
            *offset += sglen;
        } else {
}//sg为0就表示没有scatter gather list,或者说scatterlist,对于这种情况,数据将直接传送给request_buffer或者直接从request_buffer中取得数据。而如果sg大于0,那么表示scatter gather list这么一个数组就在request_buffer中,而数组元素个数正是sg个。也就是说,srb->request_buffer里边的数据有两种可能,一种是包含了数据本身,另一种是包含了scattergather list。具体是哪种情况通过判断sg来决定。而接下来即将要讲到的srb->request_bufflen顾名思义,就是buffer的长度,但对于sg大于0的情况,换言之,对于使用scatter gather list的情况,request_bufflen没有意义,将被忽略。
24.   彼岸花的传说(八) 
unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,unsigned int *offset, enum xfer_buf_dir dir)
{
offset是函数调用传递进来的参数,用来标志偏移量的,每次复制几个字节它就增加几个字节,最大它也不能超过request_bufflen。
usb_stor_access_xfer_buf()这个函数所做的事情就是从srb->request_buffer往buffer里边复制数据,或者反过来从buffer往srb->request_buffer,然后返回复制了多少个字节。对于offset大于等于request_bufflen的情况,当然就直接返回0了,因为request_buffer已经满了。
  cnt = 0;
    while (cnt < buflen && sg) {
         struct page *page = sg_page(sg) + ((sg->offset + *offset) >> PAGE_SHIFT);
        unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
        unsigned int sglen = sg->length - *offset;
        if (sglen > buflen - cnt) {
            /* Transfer ends within this s-g entry */
            sglen = buflen - cnt;
            *offset += sglen;
        } else {
            /* Transfer continues to next s-g entry */
            *offset = 0;
            sg = sg_next(sg);
        }
        /* Transfer the data for all the pages in this
            * s-g entry.  For each page: call kmap(), do the
            * transfer, and call kunmap() immediately after. */
 while (sglen > 0) {
//sglen一开始肯定应该大于0,它表示的是实际装了多少数据,但是内存管理机制有一个限制,memcpy传输不能够跨页,也就是说不能跨page,一次最多就是把本page的内容复制,如果你的数据超过了一个page,那你还得再复制一次或者多次,因为这里使用了循环。
            unsigned int plen = min(sglen, (unsigned int)
                    PAGE_SIZE - poff);
             unsigned char *ptr = kmap(page);
            if (dir == TO_XFER_BUF)
                 memcpy(ptr + poff, buffer + cnt, plen);
            else
                 memcpy(buffer + cnt, ptr + poff, plen);
            kunmap(page);
//kmap()和kunmap()内核中的内存管理部门提供的重要函数,其中kmap()函数的作用就是传递给它一个struct page指针,它能返回这个page指针所指的page的内核虚拟地址,而有了这个page对应的虚拟地址,加上前面已经知道的偏移量,就可以调用memcpy函数来复制数据了。至于kunmap,凡是kmap()建立起来的良好关系必须由kunmap()来摧毁。
            /* Start at the beginning of the next page */
            poff = 0;
            ++page;
            cnt += plen;
            sglen -= plen;
        }
    }
    *sgptr = sg;
    /* Return the amount actually transferred */
    return cnt;
//usb_stor_access_xfer_buf()这个函数,明白这个双重循环,须知外循环是按sg entry来循环的,即一个sg entry循环一次,而内循环是按page来循环的,一个sg entry可以有多个page,因为没有办法跨page映射,所以只能每个page映射一次,所以才需要循环。
//kmap()和kunmap()这两个函数是干什么的?为什么要映射?这个世界上有一个地址,叫做物理地址,还有一个地址叫做内核地址。struct page代表的是物理地址,内核用这个结构体来代表每一个物理page,或者说物理页,显然我们代码中不能直接操作物理地址,memcpy这个函数根本就不认识物理地址,它只能使用内核地址。所以我们需要把物理地址映射到内核地址空间中来。kmap()从事的正是这项伟大的工作。不过写过代码的人了解kmap()更多地是在和high memory打交道时认识的。
}
25.   彼岸花的传说(the end) 
static int  usb_stor_control_thread(void * __us)
{
 /* we've got a command, let's do it! */
        else {
            US_DEBUG(usb_stor_show_command(us, us->srb));
             us->proto_handler(us->srb, us); 
//us->proto_handler = usb_stor_transparent_scsi_command
            usb_mark_last_busy(us->pusb_dev);
        }
        /* lock access to the state */
        scsi_lock(host);
        /* indicate that the command is done */
        if (us->srb->result != DID_ABORT << 16) {
            usb_stor_dbg(us, "scsi cmd done, result=0x%x\n",
                     us->srb->result);
            us->srb->scsi_done(us->srb);
//刚才的命令的结果即srb->result不为DID_ABORT,那么就是成功执行了,于是就调用scsi_done函数.
        } else {
SkipForAbort:
            usb_stor_dbg(us, "scsi command aborted\n");
        }
        /* If an abort request was received we need to signal that
         * the abort has finished.  The proper test for this is
         * the TIMED_OUT flag, not srb->result == DID_ABORT, because
         * the timeout might have occurred after the command had
         * already completed with a different result code. */
        if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
            complete(&(us->notify));
            /* Allow USB transfers to resume */
            clear_bit(US_FLIDX_ABORTING, &us->dflags);
            clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
        }
//SkipForAbort,就是一个行标志,对应前面的goto SkipForAbort语句,如果是设置了US_FLIDX_TIMED_OUT那么就唤醒设这个flag的进程,其实就是唤醒command_abort
        /* finished working on this command */
        us->srb = NULL;
        scsi_unlock(host);
        /* unlock the device pointers */
        mutex_unlock(&us->dev_mutex);
    } /* for (;;) */
    /* Wait until we are told to stop */
     for (;;) {
        set_current_state(TASK_INTERRUPTIBLE);
        if (kthread_should_stop())
            break;
        schedule();
    }
    __set_current_state(TASK_RUNNING);
    return 0;
//程序执行到这一行意味着for循环结束了,而从for循环的代码我们不难看出,结束for循环的只有一句话,就是break。前面说过,它意味着模块要被卸载了。所以这里kthread_should_stop()就是结束自己,于是这一刻,usb_stor_control_thread()也就正式结束了,也许对它来说,结束就是解脱吧。
}
26.SCSI命令之我型我秀
static int  usb_stor_control_thread(void * __us)
{
 /* we've got a command, let's do it! */
        else {
            US_DEBUG( usb_stor_show_command(us, us->srb));
             us->proto_handler(us->srb, us); 
//us->proto_handler = usb_stor_transparent_scsi_command
            usb_mark_last_busy(us->pusb_dev);
        }
}
void usb_stor_show_command(const struct us_data *us, struct scsi_cmnd *srb)
{
执行的SCSI命令打印出来,让不熟悉SCSI的读者知道基本上会遇到一些什么命令,INQUIRY命令也包含在其中
}
27.迷雾重重的批量传输(一)

us->proto_handler()其实是一个函数指针,在storage_probe()中,在get_protocol()就赋了值,当时只知道是get_protocol,对于U盘,proto_handler被赋值为usb_stor_transparent_scsi_command。

storage_probe()--->static void get_protocol(struct us_data *us)

static int usb_stor_control_thread(void * __us)
{
  us->proto_handler(us->srb, us);
}
28.迷雾重重的批量传输(二)
void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
{
  result = us->transport(srb, us);
//这个函数指针同样是在storage_probe时被赋值,对于U盘,它遵守的是Bulk-Only协议,因此us->transport()被赋值为usb_stor_Bulk_transport()。来看usb_stor_Bulk_transport()
}

29.迷雾重重的批量传输(三)
在usb_stor_Bulk_transport()中,这个函数中调用的第一个最重要的函数,那就是usb_stor_bulk_transfer_buf()
int  usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
    void *buf, unsigned int length, unsigned int *act_len)
{
    int result;

    usb_stor_dbg(us, "xfer %u bytes\n", length);

    /* fill and submit the URB */
     usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
              usb_stor_blocking_completion, NULL);
    result =  usb_stor_msg_common(us, 0);
//作用是urb会被提交,然后核心层去调度,去执行它
    /* store the actual length of the data transferred */
    if (act_len)
        *act_len = us->current_urb->actual_length;
    return interpret_urb_result(us, pipe, length, result, 
            us->current_urb->actual_length);
}
EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
usb_fill_bulk_urb(),usb_fill_control_urb(),usb_fill_int_urb()的函数,分别对应USB传输模式中的批量、控制和中断。唯一一处与usb_fill_control_urb不同的便是,批量传输不需要有一个setup_packet。

static inline void  usb_fill_bulk_urb(struct urb *urb,
                     struct usb_device *dev,
                     unsigned int pipe,
                     void *transfer_buffer,
                     int buffer_length,
                     usb_complete_t complete_fn,
                     void *context)
{       
    urb->dev = dev;
    urb->pipe = pipe;
    urb->transfer_buffer = transfer_buffer;
    urb->transfer_buffer_length = buffer_length;
    urb->complete = complete_fn;
    urb->context = context;
}
我们调用这个函数的目的是为了填充一个urb,然后我们可以把这个urb提交给USB Core那一层。它就是为特定的管道填充一个urb(最初urb申请时被初始化为0了)。 
 
此处特意提一下usb_complete_t类型,在include/linux/usb.h中,有下面这一行。 
  
typedef void (*usb_complete_t)(struct urb *); 
  
这里用了typedef来简化声明,不熟悉typedef功能的人可以去查一下,typedef的强大使得以下两种声明作用相同。 
  
一种作用是: 
void (*func1)(struct urb *); 
void (*func2)(struct urb *);
void (*func3)(struct urb *); 
  
另一种作用是: 
  
typedef void (*usb_complete_t)(struct urb *); 
usb_complete_t func1;   ==  void (*func1)(struct urb *); 
usb_complete_t func2; 
usb_complete_t func3; 
如果要声明很多个函数指针,那么显然使用typedef一次,以后声明就很简单了。实际上urb中的complete是一个函数指针,它被设置为指向函数usb_stor_blocking_completion()。不用说,这个函数之后肯定会被调用。static void  usb_stor_blocking_completion(struct urb *urb) 
{
    struct completion *urb_done_ptr = urb->context;
    complete(urb_done_ptr);
}
static int  usb_stor_msg_common(struct us_data *us, int timeout) //作用是urb会被提交,然后核心层去调度,去执行它
{
/* set up data structures for the wakeup system */
     init_completion(&urb_done); //一个队列操作函数,调用了init_waitqueue_head去初始化一个等待队列
  
   us->current_urb->context = &urb_done;
   us->current_urb->transfer_flags = 0;

    if (us->current_urb->transfer_buffer == us->iobuf)
        us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    us->current_urb->transfer_dma = us->iobuf_dma;
//设置us的current_urb结构,transfer_flags被设置成了URB_NO_SETUP_DMA_MAP,而URB_NO_SETUP_DMA_MAP表明,如果使用DMA传输,则urb中setup_dma指针所指向的缓冲区是DMA缓冲区,而不是setup_packet所指向的缓冲区。不过这个setup_packet是控制传输特有的概念,对于批量传输,根本没有这个概念。

//us->iobuf和us->iobuf_dma,在设置URB_NO_TRANSFER_DMA_MAP这个flag时,先做了一次判断,判断us->current_urb->transfer_buffer是否等于us->iobuf,在usb_fill_bulk_urb中,把us->iobuf传递了过去,它被赋给了urb->transfer_buffer,这样做就意味着我们这里将使用DMA传输,所以这里就设置了这个flag。倘若我们不希望进行DMA传输,那很简单,我们在调用usb_stor_ msg_common之前,不让urb->transfer_buffer指向us->iobuf就行了,反正这都是我们自己设置的。需要知道的是,transfer_buffer是给各种传输方式中真正用来数据传输的,而setup_packet仅仅是在控制传输中发送Setup的包的,控制传输除了Setup阶段之外,也会有数据传输阶段,这一阶段要传输数据还是得靠transfer_buffer,而如果使用DMA方式,那么就是使用transfer_dma。


    /* submit the URB */
    status = usb_submit_urb(us->current_urb, GFP_NOIO);
// 提交urb,usb_submit_urb得到调用,作为USB设备驱动程序,我们得知道它有两个参数,一个是要提交的urb,另一个是内存申请的flag。这里我们使用的是GFP_NOIO,意思就是不能在申请内存时进行I/O操作。一个存储设备,调用usb_submit_urb很可能是因为我们要读些磁盘或者U盘,在这种情况如果申请内存的函数又再一次去读写磁盘,就会出现嵌套。什么叫申请内存的函数也会读写磁盘?因为内存不够。使用磁盘作为交换分区不就方便了,所以申请内存时可能要的内存在磁盘上,那就得交换回来。这不就读写磁盘了吗?所以我们为了读写硬盘而提交urb,那么这个过程中就不能再次有I/O操作了,这样做的目的是为了杜绝出现嵌套死循环。  
 if (status) { // 如果一切正常,status将是0
        /* something went wrong */
        return status;
    }                                                                                                           
                                                                                                                
    /* since the URB has been submitted successfully, it's now okay                                             
     * to cancel it */                                                                                          
    set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);                                                                  
                                                                                                                
    /* did an abort occur during the submission? */                                                             
    if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {                                                             
                                                                                                                
        /* cancel the URB, if it hasn't been cancelled already */                                               
        if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) { //记录urb的状态                                            
            usb_stor_dbg(us, "-- cancelling URB\n");                                                            
            usb_unlink_urb(us->current_urb);                                                                    
        }                                                                                                       
    }                                                                                                           
                                                                                                                
    /* wait for the completion of the URB */
    timeleft = wait_for_completion_interruptible_timeout(
            &urb_done, timeout ? : MAX_SCHEDULE_TIMEOUT); //时间机制
 
    clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags);

    if (timeleft <= 0) {
        usb_stor_dbg(us, "%s -- cancelling URB\n",
                 timeleft == 0 ? "Timeout" : "Signal");
        usb_kill_urb(us->current_urb);
    }




}
static inline void  init_completion(struct completion *x)
{
    x->done = 0;
    init_waitqueue_head(&x->wait);
}
设置us的current_urb结构,transfer_flags被设置成了URB_NO_SETUP_DMA_MAP,而URB_NO_SETUP_DMA_MAP表明,如果使用DMA传输,则urb中setup_dma指针所指向的缓冲区是DMA缓冲区,而不是setup_packet所指向的缓冲区。不过这个setup_packet是控制传输特有的概念,对于批量传输,根本没有这个概念。

URB_NO_TRANSFER_DMA_MAP则表明,如果urb有一个DMA缓冲区需要传输,则该缓冲区是transfer_dma指针所指向的那个缓冲区,而不是transfer_buffer指针所指向的那一个缓冲区。如果没有设置这两个DMA的flag,那么USB Core就会使用setup_packet(仅对控制传输来说有意义)和transfer_buffer作为数据传输的缓冲区,然后下面两行就是把us的iobuf_dma和cr_dma赋给了urb的transfer_dma和setup_dma。只要transfer_buffer被赋了值,那就假设有DMA缓冲区需要传输,于是就去设URB_NO_TRANSFER_DMA_MAP。
  
首先,这里是两个DMA相关的flag:URB_NO_SETUP_DMA_MAP和URB_NO_TRANSFER_DMA_MAP。注意这两个是不一样的,前一个是专门为控制传输准备的,因为只有控制传输需要有这个Setup阶段,需要准备一个Setuppacket。关于transfer_buffer和transfer_dma的关系,当初同样用下面的方法申请了us->iobuf 的内存:

(30)
迷雾重重的批量传输(四)

static int usb_stor_msg_common(struct us_data *us, int timeout)
{

set_bit(US_FLIDX_URB_ACTIVE, &us->dflags);                                                                                          
                                                                                                                                        
    /* did an abort occur during the submission? */                                                                                     
    if (test_bit(US_FLIDX_ABORTING, &us->dflags)) {                                                                                     
                                                                                                                                        
        /* cancel the URB, if it hasn't been cancelled already */                                                                       
        if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->dflags)) {                                                                     
            usb_stor_dbg(us, "-- cancelling URB\n");                                                                                    
            usb_unlink_urb(us->current_urb);                                                                                            
        }                                                                                                                               
    } 

 timeleft =  wait_for_completion_interruptible_timeout(&urb_done, timeout ? :  MAX_SCHEDULE_TIMEOUT);
//wait_for_completion是这一系列函数中最基本的,其他几个函数都是基于它的扩展函数。与wait_for_completion对应的一个函数是complete()。其用法和作用如下所示:首先我们要用init_completion初始化一个struct completion的结构体变量,然后调用wait_for_completion(),这样当前进程就会进入睡眠,处于一种等待状态,而另一个进程可能会去做某事。当它做完了某件事情之后,它会调用complete()函数,一旦它调用这个complete()函数,那么刚才睡眠的这个进程就会被唤醒。这样就实现了一种同步机制,或者叫等待机制。

//这里设置了闹钟,时间为MAX_SCHEDULE_TIMEOUT,这么做的道理就是希望别提交一个urb上去之后半天都没人理,如果真的没人理说明出问题了,别浪费时间了,先撤销这个urb重新提交吧。清除US_FLIDX_URB_ACTIVE flag,然后如果timeleft小于等于0就调用usb_kill_urb ()函数撤销当前这个urb。

//那么除了这个闹钟以外,这个同步机制如何工作init_completion(&urb_done),urb_done是一个struct completion 结构体变量,这个定义在usb_stor_ msg_common()函数的第1行就出现了。显然completion是Linux中同步机制的一个很重要的结构体。同时我们又把&urb_done作为第1个参数传递给了wait_for_completion_interruptible_timeout()。所以我们就等着看发送唤醒信号的complete()函数在哪里被调用的,换句话说,这里一旦睡去,何时才能醒来。

  clear_bit( US_FLIDX_URB_ACTIVE, &us->dflags);

    if (timeleft <= 0) {
        usb_stor_dbg(us, "%s -- cancelling URB\n",
                 timeleft == 0 ? "Timeout" : "Signal");
         usb_kill_urb(us->current_urb);
    }
 /* return the URB status */                                                                                                         
    return us->current_urb->status;  
//首先是clear_bit()清除US_FLIDX_URB_ACTIVE,表明这个urb 不再是活跃了。因为该干的事都干完了。如果是超时了,那么也是一样的,urb都要被撤销了,当然就不用设为活跃了。usb_stor_ msg_common()函数终于该返回了,return us->current_urb->status,返回的就是urb的“status”。我们将回到usb_stor_bulk_transfer_buf()中来。

//int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,void *buf, unsigned int length, unsigned int *act_len)
{
    /* fill and submit the URB */
    usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,usb_stor_blocking_completion, NULL);
还记得在调用usb_fill_bulk_urb()填充urb时设置了一个urb->complete指针吗?没错,当时咱们就看到了urb->complete=usb_stor_blocking_completion,这相当于向USB主机控制器驱动传达了一个信息。所以,当urb传输完成了之后,USB主机控制器会唤醒它,但不会直接唤醒它,而是通过执行之前设定的urb的complete()函数指针所指向的函数,即调用usb_stor_blocking_completion()函数去真正唤醒它。


}

static void  usb_stor_blocking_completion(struct urb *urb)
{   
    struct completion *urb_done_ptr = urb->context;
    complete(urb_done_ptr);
//调用complete()函数,urb_done_ptr就被赋为urb->context,usb_stor_ msg_common()函数中,把刚初始化好的urb_done赋给它,很显然,这样做就是唤醒刚才睡眠的那个进程。wait_for_completion()将醒来,从而继续往下走。
}



int  usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
{
 struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
    struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
    unsigned int transfer_length = scsi_bufflen(srb);
    unsigned int residue;
    int result;
    int fake_sense = 0;
    unsigned int cswlen;
    unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
    
    /* Take care of BULK32 devices; set extra byte to 0 */
    if (unlikely(us->fflags & US_FL_BULK32)) {
        cbwlen = 32;
        us->iobuf[31] = 0;
    }

    /* set up the command wrapper */
    bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
    bcb->DataTransferLength = cpu_to_le32(transfer_length);
    bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
        US_BULK_FLAG_IN : 0;
    bcb->Tag = ++us->tag;
    bcb->Lun = srb->device->lun;
    if (us->fflags & US_FL_SCM_MULT_TARG)
        bcb->Lun |= srb->device->id << 4;
    bcb->Length = srb->cmd_len;

    /* copy the command payload */
    memset(bcb->CDB, 0, sizeof(bcb->CDB));
    memcpy(bcb->CDB, srb->cmnd, bcb->Length);

    /* send it to out endpoint */
    usb_stor_dbg(us, "Bulk Command S 0x%x T 0x%x L %d F %d Trg %d LUN %d CL %d\n",
             le32_to_cpu(bcb->Signature), bcb->Tag,
             le32_to_cpu(bcb->DataTransferLength), bcb->Flags,
             (bcb->Lun >> 4), (bcb->Lun & 0x0F),
             bcb->Length);
//这两个数据结构对应于CBW和CSW,即Command Block Wrapper和Command Status Wrapper。我们需要关注一下USB Mass Storage Bulk-only Transport协议了,因为U盘是按照这个协议规定的方式去传输数据的。Bulk-only传输方式是首先由主机给设备发送一个CBW,然后设备接收到了CBW,它会进行解释,然后按照CBW中定义的那样去执行它该做的事情,然后它会给主机返回一个CSW。

CBW实际上是命令的封装包,而CSW实际上是状态的封装包。(命令执行后的状态,成功还是失败呢?所以需要使用这么一个状态包)。

调用usb_stor_bulk_transfer_buf()之前的那几行都是在为usb_stor_bulk_transfer_buf()这个函数调用做准备,真正精彩的部分还是在usb_stor_bulk_transfer_buf()中。

9struct bulk_cb_wrap *bcb,赋值为(struct bulk_cb_wrap *)us->iobuf。struct bulk_cs_wrap *bcs,也赋值为(struct bulk_cb_wrap *)us->iobuf,然后定义一个unsigned int的变量transfer_length,赋值为srb->request_bufflen。然后接下来就开始为bcb的各成员赋值了。

  result =  usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb, cbwlen, NULL);
//
}

usb_stor_Bulk_transport()函数,usb_stor_bulk_transfer_buf()函数得到调用。第1个参数,us。第2个参数,us->send_bulk_pipe,作为U盘来说,它除了有一个控制管道以外,还会有两个批量管道,一个是IN,一个是OUT。管道就是一个unsigned int类型的数。us->send_bulk_pipe和接下来我们立刻会遇到的us->recv_bulk_pipe都是在曾经那个令人回味的storage_probe()中调用get_pipes()函数获得的。然后第3个参数bcb。

定义了这么一个指针bcb,是structbulk_cb_wrap结构体的指针,这是一个专门为Bulk-only协议特别准备的数据结构
/* command block wrapper */
struct bulk_cb_wrap {
    __le32  Signature;      /* contains 'USBC' */                                                                                       
    __u32   Tag;            /* unique per command id */                                                                                 
    __le32  DataTransferLength; /* size of data */
    __u8    Flags;          /* direction in bit 0 */                                                                                    
    __u8    Lun;            /* LUN normally 0 */
    __u8    Length;         /* of of the CDB */
    __u8    CDB[16];        /* max command */                                                                                           
};

/* command status wrapper */
struct bulk_cs_wrap {
    __le32  Signature;  /* should = 'USBS' */
    __u32   Tag;        /* same as original command */
    __le32  Residue;    /* amount not transferred */
    __u8    Status;     /* see below */
};



图一

图二

bcb->Signature=cpu_to_le32(US_BULK_CB_SIGN),Signature对应USB Mass Storage spec中CBW的前4个Bytes,即dCBWSignature
#define US_BULK_CB_SIGN     0x43425355  /*spells out USBC */
也不知道是谁规定的,只有把dCBWSignature里边写上43425355h才能标志着个数据包是一个CBW。另外,CBW的传输全是遵守Little Endian的,所以cpu_to_le32()这个宏需要使用,来转换数据格式。

bcb->DataTransferLength对应CBW中的dCBWDataTransferLength。这个就是标志ho主机希望这个端点传输多少个Bytes的数据。这里把cpu_to_le32(transfer_length)赋给了它。而transfer_length刚才已经说了,就是srb->request_bufflen。

bcb->Flags,对应于CBW中的bmCBWFlags,bcb->Flags =srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;表明的是数据传输的方向,DMA_FROM_DEVICE在前面讲过,表示数据是从设备传向主存。而bmCBWFlags是8位的,其中bit7表示方向;0表示Data-Out,即from host to the device;1表示Data-in,即from the device to the host。所以这里如果是1的话要左移7位。

bcb->Tag = srb-&gt;serial_number,这个Tag对应CBW中的dCBWTag,dCBWTag的意义在于,主机会send出去,而设备将会把这个Tag的内容给打印出来。设备会回送一个CSW回来,而在CSW中会有一个dCSWTag,它的内容和这个dCBWTag是一样的,所以实际上这就跟接头暗号似的。每一个SCSI命令都会被赋上一个serial_number,这里把它用在了Tag上。


bcb->Lun = srb-&gt;device->lun,对应CBW中的bCBWLUN,就是表示这个命令是发给哪个LUN的,一个设备如果支持多个LUN,那么显然每个LUN会有一个编号。比如要读写U盘上的某个分区,那么当然得指明是哪个分区了。如果设备不支持多个LUN,那么这儿会被设置为0。不过bcb->Lun和CBW中的bCBWLUN并不完全对应,bCBWLUN只有4个bit,LUN是有8位的,低4位用来对应bCBWLUN,而高4位实际上是用来表示target id的。所以接下来判断us->flags里边设了US_FL_SCM_MULT_TARG这个标志没有,如果有,说明是支持多个target的,于是就要记录下是哪个target。

bcb->Length = srb-&gt;cmd_len,这个对应于CBW中的bCBWCBLength,即命令的有效长度,单位是Bytes。SCSI命令的有效长度只能是1到16之间。接下来有个CDB数组,数组共16个元素,理由在前面讲struct scsi_cmnd中的cmnd就已经说过了。把命令srb->cmnd数组的内容复制至bcb->CDB中。

usb_stor_bulk_transfer_buf正式被调用了。传递给它的第三个参数正是bcb,而第四个参数是US_BULK_CB_WRAP_LEN
#define US_BULK_CB_WRAP_LEN 31

int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
 { 
result =  usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
                bcb, cbwlen, NULL);
    usb_stor_dbg(us, "Bulk command transfer result=%d\n", result);
    if (result != USB_STOR_XFER_GOOD)
        return USB_STOR_TRANSPORT_ERROR;
}


int  usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
    void *buf, unsigned int length, unsigned int *act_len)
{
    int result;

    usb_stor_dbg(us, "xfer %u bytes\n", length);

    /* fill and submit the URB */
    usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
              usb_stor_blocking_completion, NULL);
    result = usb_stor_msg_common(us, 0);

    /* store the actual length of the data transferred */
    if (act_len)
        *act_len = us->current_urb->actual_length;
    return interpret_urb_result(us, pipe, length, result, 
            us->current_urb->actual_length);
}
EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_buf);
//CBW的长度,CBW正是31个Bytes。而usb_stor_bulk_transfer_buf无非就是提交一个urb,然后就不用管事了,就等结果呗。而最终的结果是由interpret_urb_result()返回的,传输正确那么会返回USB_STOR_XFER_GOOD,而如果不正确,那么usb_stor_Bulk_transport()中就直接返回了,返回值是USB_STOR_TRANSPORT_ERROR。如果正确,那么继续往下走,这才到真正的数据传输阶段。在真正开始将数据传输阶段之前,我们先来查看interpret_urb_result()函数。


(31)
迷雾重重的批量传输(五)

static int  interpret_urb_result(struct us_data *us, unsigned int pipe,                                                                  
        unsigned int length, int result, unsigned int partial)                                                                          
{                                                                                                                                       
    usb_stor_dbg(us, "Status code %d; transferred %u/%u\n",                                                                             
             result, partial, length);                                                                                                  
    switch ( result) {                                                                                                                   
                                                                                                                                        
    /* no error code; did we send all the data? */                                                                                      
    case 0:                                                                                                                             
        if (partial != length) {                                                                                                        
            usb_stor_dbg(us, "-- short transfer\n");                                                                                    
            return USB_STOR_XFER_SHORT;                                                                                                 
        }                                                                                                                               
                                                                                                                                        
        usb_stor_dbg(us, "-- transfer complete\n");                                                                                     
        return USB_STOR_XFER_GOOD;                                                                                                      
                                                                                                                                        
    /* stalled */                                                                                                                       
    case -EPIPE:                                                                                                                        
        /* for control endpoints, (used by CB[I]) a stall indicates                                                                     
         * a failed command */                                                                                                          
        if (usb_pipecontrol(pipe)) {                                                                                                    
            usb_stor_dbg(us, "-- stall on control pipe\n");                                                                             
            return USB_STOR_XFER_STALLED;                                                                                               
        }                                                                                                                               
                                                                                                                                        
        /* for other sorts of endpoint, clear the stall */                                                                              
        usb_stor_dbg(us, "clearing endpoint halt for pipe 0x%x\n",                                                                      
                 pipe);                                                                                                                 
        if (usb_stor_clear_halt(us, pipe) < 0)                                                                                          
            return USB_STOR_XFER_ERROR;                                                                                                 
        return USB_STOR_XFER_STALLED;                                                                                                   
                                                                                                                                        
    /* babble - the device tried to send more than we wanted to read */ 
}
//这个函数的作用根据传进来的参数result进行判断,从而采取相应的行动。partial是实际传输的长度,而length是期望传输的长度,传输结束了当然要比较这两者。result是usb_stor_ msg_common()函数的返回值,其实就是状态代码。如果为0说明一切都很顺利,结果也是成功的。
  
然后通过一个switch语句判断result,为0,说明至少数据有传输。然后有两种情况,于是返回不同的值,USB_STOR_XFER_SHORT和USB_STOR_XFER_GOOD。至于返回这些值之后会得到什么反应,让我们边走边看。目前只需要知道的是,对于真正传输完全令人满意的情况,返回值只能是USB_STOR_XFER_GOOD。返回其他值都说明有问题。而这里作为传递给switch的result,实际上是USB Core那一层传过来的值。

//interpret_urb_result这个函数整个是被作为一个返回值出现在usb_stor_bulk_transfer_buf()中的。前者返回之后,后者也马上就返回了,即再次返回到了usb_stor_Bulk_transport()中。回到usb_stor_Bulk_transport(),如果result不为USB_STOR_XFER_GOOD,就说明有一些问题,于是索性usb_stor_Bulk_transport()也返回,没必要再进行下一阶段的传输了。否则,才可以进行下一阶段。



int  usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,                                                                 
        void *buf, unsigned int length_left, int use_sg, int *residual)                                                              
{                                                                                                                                    
    int result;                                                                                                                      
    unsigned int partial;                                                                                                            
                                                                                                                                     
    /* are we scatter-gathering? */                                                                                                  
    if (use_sg) {                                                                                                                    
        /* use the usb core scatter-gather primitives */                                                                             
        result = usb_stor_bulk_transfer_sglist(us, pipe,                                                                             
                (struct scatterlist *) buf, use_sg,                                                                                  
                length_left, &partial);                                                                                              
        length_left -= partial;                                                                                                      
    } else {                                                                                                                         
        /* no scatter-gather, just make the request */                                                                               
        result = usb_stor_bulk_transfer_buf(us, pipe, buf,                                                                           
                length_left, &partial);                                                                                              
        length_left -= partial;                                                                                                      
    }                                                                                                                                
                                                                                                                                     
    /* store the residual and return the error code */                                                                               
    if (residual)                                                                                                                    
        *residual = length_left;                                                                                                     
    return result;                                                                                                                   
}                                                                                                                                    
EXPORT_SYMBOL_GPL(usb_stor_bulk_transfer_sg); 
调用或者说利用的那两个函数:usb_stor_bulk_transfer_sglist()和usb_stor_bulk_transfer_buf()。前者是专门为scatter-gather传输准备的函数

在usb_stor_bulk_transfer_sg()函数中,判断use_sg是否为0,从而确定是否用scatter-gather。对于use_sg等于0的情况,表示不用scatter-gather,那么调用usb_stor_bulk_transfer_buf()发送scsi命令。实际传递的数据长度用partial记录,然后length_left就记录还剩下多少没传递,初值当然就是期望传递的那个长度。每次减去实际传递的长度即可。对于use_sg不等于0的情况,usb_stor_bulk_transfer_sglist()函数被调用。


(32)
迷雾重重的批量传输(六)

int  usb_stor_bulk_transfer_sg(struct us_data* us, unsigned int pipe,void *buf, unsigned int length_left, int use_sg, int *residual)
{
    int result;
    unsigned int partial;
            
    /* are we scatter-gathering? */
    if (use_sg) {
        /* use the usb core scatter-gather primitives */
        result = usb_stor_bulk_transfer_sglist(us, pipe,
                (struct scatterlist *) buf, use_sg,
                length_left, &partial);
        length_left -= partial;
    } else {
        /* no scatter-gather, just make the request */
        result = usb_stor_bulk_transfer_buf(us, pipe, buf, 
                length_left, &partial);
        length_left -= partial;
    }

    /* store the residual and return the error code */
    if (residual)
        *residual = length_left;
    return result;

}

usb_stor_bulk_transfer_sglist()采用sglist,就是为了提高传输效率。sg的目的就是让一堆不连续的buffers在一次DMA操作都传输出去。

static int  usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,struct scatterlist *sg, int num_sg, unsigned int length,unsigned int *act_len)
{
  result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,sg, num_sg, length, GFP_NOIO);

/* wait for the completion of the transfer */
    usb_sg_wait(&us->current_sg);
    clear_bit(US_FLIDX_SG_ACTIVE, &us->dflags);

    result = us->current_sg.status;
    if (act_len)
        *act_len = us->current_sg.bytes;
    return interpret_urb_result(us, pipe, length, result,
            us->current_sg.bytes);
//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,然后返回之前,再来一次调用interpret_urb_result()转换一下结果。
}

usb_sg_init()函数被调用,它是USB核心层提供的函数,初始化sg请求。其第1个参数是struct usb_sg_request结构体的指针。这里我们传递了us->current_sg的地址给它。

struct us_data {
 struct usb_sg_request   current_sg;  /* scatter-gather req.  */
}

在struct us_data中,定义了一个成员struct usb_sg_request current_sg。曾几何时我们见到过current_urb,这里又来了一个current_sg。struct urb表示的是一个USB请求,而这里struct usb_sg_request实际上表示一个scattergather request,从我们非USB核心层的人来看,这两个结构体的用法是一样的。对于每次urb请求,我们所做的只是申请一个结构体变量或者说申请指针,然后申请内存,第二步就是提交urb,即调用usb_submit_urb(),剩下的事情USB Core就会去帮我们处理了,Linux中的每个模块都给别人服务,也同时享受着别人提供的服务。

你要想跟别人协同工作,只要按照人家提供的函数去调用,把你的指针你的变量传递给别人,其他你根本不用管,事成之后自然会通知你。同样对于sg request,USB Core也实现了这些,我们只需要申请并初始化一个struct usb_sg_request的结构体,然后提交,USB Core自然就知道该怎么处理了。

struct  usb_sg_request { //表示一个scattergather request
    int         status;
    size_t          bytes;
    /* private:
     * members below are private to usbcore,
     * and are not provided for driver access!
     */
    spinlock_t      lock;
    struct usb_device   *dev;
    int         pipe;
    int         entries;
    struct urb      **urbs;   
    int         count;
    struct completion   complete;
};
 
整个USB系统都会使用这个数据结构,如果我们希望使用scatter gather方式的话。USB Core已经为我们准备好了数据结构和相应的函数,我们只需要调用即可。一共有3个函数,它们分别是usb_sg_init,usb_sg_wait,usb_sg_cancel。我们要提交一个sg请求,需要做的是先用usb_sg_init来初始化请求,然后usb_sg_wait()正式提交。如果想撤销一个sg请求,那么调用usb_sg_cancel即可。

result =  usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0,sg, num_sg, length, GFP_NOIO);
usb_sg_init()被调用时传递给它的参数:
第1个 刚才已经说了,就是sgrequest
第2个 需要告诉它是哪个USB设备要发送或接收数据,我们给它传递的是us->pusb_dev
第3个 是哪个管道,这个没什么好说的,管道是上面一路传下来的
第4个 这是专门适用于中断传输的,被传输中断端点的轮询率,对于批量传输,直接忽略,所以我们传递了0
第5个和第6个参数就分别是sg数组和sg数组中元素的个数
第7个参数 length,传递的就是我们希望传输的数据长度
最后一个 是slab flag,内存申请相关的一个flag。如果驱动程序处于block I/O路径中应该使用GFP_NOIO,这里SLAB_NOIO实际上是一个宏,实际上就是GFP_NOIO  前面函数也调用usb_submit_urb()的时候也用了slab flag


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 MassStorage 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会通知你。你就可以接下来干别的事情了。


(33)
迷雾重重的批量传输(六)

int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
{
/* get CSW for device status */
    usb_stor_dbg(us, "Attempting to get CSW...\n");
    result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                bcs, US_BULK_CS_WRAP_LEN, &cswlen);

    /* Some broken devices add unnecessary zero-length packets to the
     * end of their data transfers.  Such packets show up as 0-length
     * CSWs.  If we encounter such a thing, try to read the CSW again.
     */
    if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
        usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
        result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                bcs, US_BULK_CS_WRAP_LEN, &cswlen);
    }

    /* did the attempt to read the CSW fail? */
    if (result == USB_STOR_XFER_STALLED) {

        /* get the status again */
        usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
        result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
                bcs, US_BULK_CS_WRAP_LEN, NULL);
    }
}



(34)
跟着感觉走(一)


(35)
跟着感觉走(二)

















猜你喜欢

转载自blog.csdn.net/sinat_37817094/article/details/80603613