对于整个usb-storage模块,usb_stor_init()函数是它的开始,然而,对于U盘驱动程序来说,它真正驱使U盘工作却是始于storage_probe()函数。

两条平行线只要相交,就注定开始纠缠一生,不管中间是否短暂分离。USB Core为设备找到了适合它的驱动程序,或者为驱动程序找到了它所支持的设备,但这只是表明双方的第一印象还可以,但彼此是否真的适合对方还需要进一步了解。而U盘驱动则会调用函数storage_probe()去认识对方,它是一个什么样的设备?这里调用了四个函数get_device_info,get_protocol,get_transport,get_pipes。

整个U盘驱动这部大戏,由storage_probe开始,由storage_disconnect结束。其中,storage_probe这个函数占了相当大的篇幅。我们一段一段来看。这两个函数都来自drivers/usb/storage/usb.c中:

945 /* Probe to see if we can drive anewly-connected USB device */

946 static int storage_probe(struct usb_interface*intf,

947                         const struct usb_device_id *id)

948 {

949    structScsi_Host *host;

950    structus_data *us;

951    intresult;

952    structtask_struct *th;

953

954    if(usb_usual_check_type(id, USB_US_TYPE_STOR))

955          return -ENXIO;

956

957   US_DEBUGP("USB Mass Storagedevice detected\n");

958

959    /*

960     * Ask the SCSI layer to allocate a hoststructure, with extra

961     * space at the end for our privateus_data structure.

962      */

963    host =scsi_host_alloc(&usb_stor_host_template, sizeof(*us));

964    if (!host){

965       printk(KERN_WARNING USB_STORAGE

966                        "Unable to allocate the scsi host\n");

967         return -ENOMEM;

968  }

969

970    us =host_to_us(host);

971    me mset(us,0, sizeof(struct us_data));

首先先贴出这么几行,两个参数不用多说了,struct usb_interface和struct usb_device_id的这两个指针都是前面介绍过的,来自USB Core一层,我们整个故事里用到的就是这么一个,这两个指针的指向是定下来的。

950行,最重要的一个数据结构终于出现了。整个usb-storage模块里边自己定义的数据结构不多,但是us_data算一个。这个数据结构是跟随我们的代码一直走下去的,如影随形,几乎处处都可以看见它的身影。先把它的代码“贴”出来,来自drivers/usb/storage/usb.h:

102 /* we allocate one of these for every devicethat we remember */

103 struct us_data {

104    /* Thedevice we're working with

105     * It's important to note:

106     *    (o) you must hold dev_mutex to change pusb_dev

107      */

108    structmutex           dev_mutex;       /* protect pusb_dev */

109    structusb_device      *pusb_dev;       /* this usb_device */

110    structusb_interface   *pusb_intf;      /* this interface */

111     structus_unusual_dev   *unusual_dev;/* device-filter entry */

112    unsignedlong          flags;          /*from filter initially */

113    unsignedint           send_bulk_pipe;  /* cachedpipe values */

114     unsignedint           recv_bulk_pipe;

115    unsignedint           send_ctrl_pipe;

116    unsignedint           recv_ctrl_pipe;

117     unsignedint           recv_intr_pipe;

118

119    /*information about the device */

120    char                   *transport_name;

121    char                   *protocol_name;

122    __le32                 bcs_signature;

123    u8                      subclass;

124    u8                     protocol;

125    u8                     max_lun;

126

127    u8                     ifnum;           /*interface number   */

128     u8                     ep_bInterval;   /* interrupt interval */

129

130    /*function pointers for this device */

131    trans_cmnd             transport;    /*transport function    */

132    trans_reset            transport_reset; /* transport devicereset */

133    proto_cmnd             proto_handler; /* protocol handler       */

134

135    /* SCSIinterfaces */

136     structscsi_cmnd        *srb;           /* current srb         */

137     unsignedint           tag;            /* current dCBWTag     */

138

139     /*control and bulk communications data */

140    structurb             *current_urb;   /* USB requests        */

141    structusb_ctrlrequest  *cr;            /* control requests    */

142    struct usb_sg_request   current_sg;    /* scatter-gather req.  */

143     unsignedchar          *iobuf;          /* I/Obuffer           */

144    unsignedchar          *sensebuf;       /* sense data buffer    */

145    dma_addr_t             cr_dma;          /* bufferDMA addresses */

146    dma_addr_t             iobuf_dma;

147

148    /* mutualexclusion and synchronization structures */

149   struct semaphore       sema;          /* to sleepthread on     */

150   struct completion       notify;        /* thread begin/end        */

151    wait_queue_head_t       delay_wait;      /* wait duringscan, reset */

152

153    /*subdriver information */

154    void                   *extra;          /* Any extradata          */

155  extra_data_destructor extra_destructor;/*extra data destructor  */

156 #ifdef CONFIG_PM

157    pm_hook                suspend_resume_hook;

158 #endif

159 };

不难发现,Linux内核中每一个重要的数据结构都很复杂。总之,这个令人头疼的数据结构是每一个设备都有的。换句话说,我们会为每一个设备申请一个us_data,因为这个结构中边的东西我们之后一直会用得着的。950行,structus_data *us,于是,日后我们会非常频繁地看到us的。另,us什么意思?us,即usb storage。

963行,关于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结构体。关于这个usb_stor_host_template,它的定义或者说初始化是在drivers/usb/storage/scsiglue.c中:

441 struct scsi_host_templateusb_stor_host_template = {

442   /* basic userland interface stuff*/

443   .name =                        "usb-storage",

444    .proc_name=                   "usb-storage",

445   .proc_info =                   proc_info,

446    .info=                        host_info,

447

448   /* command interface -- queued only*/

449    .queuecommand=                queuecommand,

450

451     /*error and abort handlers */

452    .eh_abort_handler=            command_abort,

453    .eh_device_reset_handler=     device_reset,

454     .eh_bus_reset_handler=         bus_reset,

455

456    /* queuecommands only, only one command per LUN */

457    .can_queue=               1,

458     .cmd_per_lun=             1,

459

460     /*unknown initiator id */

461    .this_id=                     -1,

462

463     .slave_alloc=                 slave_alloc,

464    .slave_configure=             slave_configure,

465

466    /* lots ofsg segments can be handled */

467     .sg_tablesize=                SG_ALL,

468

469     /*limit the total size of a transfer to 120 KB */

470     .max_sectors=             240,

471

472    /* mergecommands... this see ms to help performance, but

473     * periodically someone should test tosee which setting is more

474     * optimal.

475      */

476   .use_clustering =           1,

477

478    /*emulated HBA */

479    .emulated=                1,

480

481     /*we do our own delay after a device or bus reset */

482   .skip_settle_delay =        1,

483

484     /*sysfs device attributes */

485    .sdev_attrs=                  sysfs_device_attr_list,

486

487    /* modulemanagement */

488    .module=                      THIS_MODULE

489 };

按照SCSI层的规矩,要想申请一个SCSI Host,并且让它工作,我们需要调用三个函数,第一个是scsi_host_alloc(),第二个是scsi_add_host(),第三个是scsi_scan_host()。这三个函数我们都会在接下来的代码里面看到。

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(),这两个明显是一对,都定义于drivers/usb/storage/usb.h:

161 /* Convert between us_data and thecorresponding Scsi_Host */

162 static inline struct Scsi_Host*us_to_host(struct us_data *us) {

163    returncontainer_of((void *) us, struct Scsi_Host, hostdata);

164 }

165 static inline struct us_data*host_to_us(struct Scsi_Host *host) {

166    return(struct us_data *) host->hostdata;

167 }

总之咱们这么一折腾,就让USB驱动和SCSI Host联系起来。从此以后这个U盘既要扮演U盘的角色又要扮演SCSI设备的角色。

957行,US_DEBUGP是一个宏,来自drivers/usb/storage/debug.h,接下来很多代码中我们也会看到这个宏,它无非就是打印一些调试信息。debug.h中有这么一段:

51 #ifdef CONFIG_USB_STORAGE_DEBUG

52 void usb_stor_show_command(struct scsi_cmnd*srb);

53 void usb_stor_show_sense( unsigned char key,

54                unsigned char asc, unsigned char ascq );

55 #define US_DEBUGP(x...) printk( KERN_DEBUGUSB_STORAGE x )

56 #define US_DEBUGPX(x...) printk( x )

57 #define US_DEBUG(x) x

58 #else

59 #define US_DEBUGP(x...)

60 #define US_DEBUGPX(x...)

61 #define US_DEBUG(x)

62 #endif

这里一共定义了几个宏,US_DEBUGP,US_DEBUGPX,US_DEBUG,差别不大,只是形式上略有不同罢了。

需要注意的是,这些调试信息得是我们打开了编译选项CONFIG_USB_STORAGE_DEBUG才有意义的,如果这个选项为0,那么这几个宏就什么也不干,因为它们被赋为空了。关于US_DEBUG系列的这几个宏,就讲到这了。

954行,usb_usual_check_type()干什么用的?这个函数来自drivers/usb/storage/libusual.c中:

98 int usb_usual_check_type(const struct usb_device_id*id, int caller_type)

99 {

100   int id_type =USB_US_TYPE(id->driver_info);

101

102     if(caller_type <= 0 || caller_type >= 3)

103          return -EINVAL;

104

105    /* Driversgrab fixed assignment devices */

106   if (id_type == caller_type)

107        return 0;

108    /* Driversgrab devices biased to them */

109  if (id_type==USB_US_TYPE_NONE&& caller_type==atomic_read(&usu_bias))

110       return 0;

111   return -ENODEV;

112 }

这个函数保证现在认领的这个设备属于usb-storage所支持的设备,而不是另一个叫做ub的驱动所支持的设备,如果你足够细心可能会注意到,drivers/block目录下面竟然也有一段与usb相关的驱动代码,它就是drivers/block/ub.c。实际上ub是一个简化版的usb-storage和sd两个模块的结合体,它的功能比较弱,但是要更稳定。如果感兴趣的话可以去读一下ub这个模块的代码。

《Linux那些事儿之我是USB》我是U盘(12)梦开始的地方相关推荐

  1. Linux那些事儿 之 戏说USB(19)设备

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1807800 第一眼看到struct usb_device这个结构,我仿佛置身于衡山路的酒吧里 ...

  2. 【转】Linux那些事儿 之 戏说USB(19)设备

    第一眼看到struct usb_device这个结构,我仿佛置身于衡山路的酒吧里,盯着舞池里扭动的符号,眼神迷离. 交大里苟了几年,毕业了又是住在学校附近的徐虹北路上,沿着虹桥路走过去,到徐家汇不过1 ...

  3. Linux那些事儿 之 戏说USB(5)我是谁

    我是谁?USB一遍一遍问着自己,当然它不会真的是一颗树.USB只是Linux庞大家族里的一个小部落,host controller是它们的族长,族里的每个USB设备都需要被系统识别,被我们识别.虽然清 ...

  4. Linux那些事儿 之 戏说USB(3)我是一棵树

    从拓扑上来看,USB子系统并不以总线的方式来部署,它是一颗由几个点对点的连接构成的树. 它主要包括了USB连接.USB host controller和USB device三个部分.而USB devi ...

  5. Linux那些事儿 之 戏说USB(33)字符串描述符

    关于字符串描述符,前面的前面已经简单描述过了,地位仅次于设备/配置/接口/端点四大描述符,那四大设备必须得支持,而字符串描述符对设备来说则是可选的. 这并不是就说字符串描述符不重要,对咱们来说,字符串 ...

  6. Linux那些事儿 之 戏说USB(25)设备的生命线(八)

    回到struct usb_hcd,继续努力的往下看. 7行,又见kref,usb主机控制器的引用计数.struct usb_hcd也有自己专用的引用计数函数,看drivers/usb/core/hcd ...

  7. Linux那些事儿 之 戏说USB(22)设备的生命线(五)

    下面接着看那三个基本点. 第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义. struct ur ...

  8. Linux那些事儿 之 戏说USB(大结局)还是那个match

    从上次在几米的向左走向右走遇到usb总线的那个match函数usb_device_match()开始到现在,遇到了设备,遇到了设备驱动,遇到了接口,也遇到了接口驱动,期间还多次遇到usb_device ...

  9. Linux那些事儿 之 戏说USB(23)设备的生命线(二)

    转载地址:http://blog.csdn.net/fudan_abc/article/details/1814938 现在设备的struct usb_device结构体已经准备好了,只是还不怎么饱满 ...

  10. 【转】Linux那些事儿 之 戏说USB(23)设备的生命线(二)

    现在设备的struct usb_device结构体已经准备好了,只是还不怎么饱满,hub接下来就会给它做做整容手术,往里边儿塞点什么,充实一些内容,比如:将设备的状态设置为Powered,也就是加电状 ...

最新文章

  1. 【第六期】拿不到offer全额退款 人工智能工程师培养计划招生
  2. html可以导入MySQL吗_将数据从HTML文件(带有嵌入式JavaScript)导入MySQL数据库
  3. vb红绿灯自动切换_什么是自动驻车
  4. HSRP (不同VLAN之间的热备份路由协议)
  5. probable oracle net,ORA-28547: connection to server failed, probable Oracle Net admin error
  6. Scala语言整理(一)
  7. 给wordpress最新文章添加“new”标记
  8. 1. 在虚拟机中 添加内容
  9. python工作台_FreeCAD二次开发-创建Python工作台,添加菜单栏和工具条,FreeCAD命令
  10. python重载运算符乘法_Python | 使用乘法运算符创建一个字符串的多个副本
  11. IDEA 快速创建 SpringBoot 项目
  12. java如何操作视图
  13. Linux 高性能服务器编程——多进程编程
  14. mysql 多表查询详解_(转)Mysql 多表查询详解
  15. hsqldb mysql_HSQLDB创建数据库和基本的数据库访问 | 学步园
  16. 数据同步工具kettle
  17. hadoop 编程规范(hadoop专利分析)
  18. linux系统查看ssh是否开启,linux查看与开启ssh
  19. python协程详解
  20. ubuntu 18.04下greenplum安装笔记(二)安装Greenplum的失败的尝试

热门文章

  1. php consult用法,咪狐API 使用手册
  2. 百度中科大“大学生创业家成长计划”开始啦!
  3. GSL 系列 6 — 线性代数 4 — LQ 分解
  4. (五)嵌入式:设置UART波特率并实现转变字符串大小,实现人机交互
  5. 【Python】数据加密解密技术
  6. 用友U8固定资产打开卡片管理报91错误
  7. 高德地图-绘制个人历史位置路线
  8. SQL 事务日志已满
  9. qt更新组件时,提示无法下载存档
  10. 栈内存和堆内存Java(详细实例讲解)