Linux那些事儿之我是U盘(25)第一次亲密接触(一)

直到现在我们才将第一次真正的开始接触usb的四种数据传输之一,控制传输.应该说从这一刻开始,代码开始变得复杂了.不过不要怕,有我在.在这个美妙的夏夜,让我们剪一段月光,来解代码的霜.

769777,做了一件事情,确定这个设备的max lun.不要说你不知道什么是max lun.不知道的回去跪主板吧,我很负责任的向你推荐我们Intel最新的3系列整合芯片组主板.

get_transport()函数中,我们针对各种情况给us->max_lun赋了值,但是我们当时就注意到了,唯独对于Bulk-Only的设备,当时并没有赋值,所以这里我们看到,对于us->protocol等于US_PR_BULK的情况,有一个专门的函数来获得这个设备的max lun.网友女为悦己者__容好奇的问,为什么写代码的同志在这里对Bulk-Only的设备表现出一种偏偏喜欢你的态度呢?没什么特别的,党中央规定的.所有的usb设备遵守一个规范,这个规范叫做usb spec,usb设备分为很多种类,usb mass storage是其中一类,mass storage设备又分为很多子类,每个子类又有它自己的规范,比如U盘它所遵守的就是usb mass storage class bulk-only transport spec.而这个规范说得很清楚,对于这种设备,它的lun不是凭感觉就能判断的,你得发送一个命令给它,向它去查询,然后它会做出响应,这样你才能知道它究竟是几个lun.这条命令就是GET MAX LUN”,详见spec 3.2.

所以我们即使不认真看这个函数也可以知道究竟发生了什么.而且我们之前还说过,普通的U盘的max lun肯定是0.对于那种读卡器才可能有多个lun.不过我们还是不妨来深入的看一下这个函数,毕竟这个函数是在drivers/usb/storage/transport.c,属于我们的辖区.当然更重要的是,此前我们一直没有真正见识过究竟一次usb传输是怎么回事,作为usb设备驱动程序究竟如何发起usb传输,而这个函数正好给了我们一次不错的机会.同时我们也将会知道,了解了一次控制传输之后,别的传输也会很容易理解.

首先我们知道这次传输的目的是为了获得一个数字,max lun,而获得这个数据的方式是发送命令,所以整个过程就是,你发送一个命令给设备,设备返回一个值给你,这么简单的传输叫什么?控制传输.很显然,地球人都知道,控制传输是usb四种传输方式中最简单的那种.来看具体代码:

 908 /* Determine what the maximum LUN supported is */
    909 int usb_stor_Bulk_max_lun(struct us_data *us)
    910 {
    911         int result;
    912
    913         /* issue the command */
    914         result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
    915                                  US_BULK_GET_MAX_LUN,
    916                                  USB_DIR_IN | USB_TYPE_CLASS |
    917                                  USB_RECIP_INTERFACE,
    918                                  0, us->ifnum, us->iobuf, 1, HZ);
    919
    920         US_DEBUGP("GetMaxLUN command result is %d, data is %d/n",
    921                   result, us->iobuf[0]);
    922
    923         /* if we have a successful request, return the result */
    924         if (result > 0)
    925                 return us->iobuf[0];
    926
    927         /*
    928          * Some devices (i.e. Iomega Zip100) need this -- apparently
    929          * the bulk pipes get STALLed when the GetMaxLUN request is
    930          * processed.   This is, in theory, harmless to all other devices
    931          * (regardless of if they stall or not).
    932          */
    933         if (result == -EPIPE) {
    934                 usb_stor_clear_halt(us, us->recv_bulk_pipe);
    935                 usb_stor_clear_halt(us, us->send_bulk_pipe);
    936         }
    937
    938         /*
    939          * Some devices don't like GetMaxLUN.  They may STALL the control
    940          * pipe, they may return a zero-length result, they may do nothing at
    941          * all and timeout, or they may fail in even more bizarrely creative
    942          * ways.  In these cases the best approach is to use the default
    943          * value: only one LUN.
    944          */
    945         return 0;
    946 }

代码不长,不过并不容易.首先914, usb_stor_control_msg()函数被调用,这也是我们自己定义的函数,所以也得讲,同样来自drivers/usb/storage/transport.c:

209
    210 /*
    211  * Transfer one control message, with timeouts, and allowing early
    212  * termination.  Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx.
    213  */
    214 int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
    215                  u8 request, u8 requesttype, u16 value, u16 index,
    216                  void *data, u16 size, int timeout)
    217 {
    218         int status;
    219
    220         US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u/n",
    221                         __FUNCTION__, request, requesttype,
    222                         value, index, size);
    223
    224         /* fill in the devrequest structure */
    225         us->cr->bRequestType = requesttype;
    226         us->cr->bRequest = request;
    227         us->cr->wValue = cpu_to_le16(value);
    228         us->cr->wIndex = cpu_to_le16(index);
    229         us->cr->wLength = cpu_to_le16(size);
    230
    231         /* fill and submit the URB */
    232         usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
    233                          (unsigned char*) us->cr, data, size,
    234                          usb_stor_blocking_completion, NULL);
    235         status = usb_stor_msg_common(us, timeout);
    236
    237         /* return the actual length of the data transferred if no error */
    238         if (status == 0)
    239                 status = us->current_urb->actual_length;
    240         return status;
    241 }

这里相对麻烦一点的函数是usb_stor_msg_common,仍然是我们自己定义的函数,所以我们又得继续往下一层看,这么多层函数调用的确挺让人看了头晕,一个人总要走陌生的路,看陌生的风景,听陌生的歌,然后在某个不经意的瞬间,你会发现,原本费尽心机想要弄清楚的函数就这么把自己弄糊涂了.然而,就像世上的每一条路都是弯的一样,每一个模块都会有曲折的函数调用,写代码的哥们儿为了表现自己一流的编剧水平,永远不会让我们一路平稳的看完整个模块的.除了面对,我们别无选择,毕竟从我们年幼时,摇篮就告诉我们,人生是不平静的,也是动荡的,所以为何不微笑着面对这些麻烦?这个函数仍旧是来自drivers/usb/storage/transport.c:

132 /* This is the common part of the URB message submission code
    133  *
    134  * All URBs from the usb-storage driver involved in handling a queued scsi
    135  * command _must_ pass through this function (or something like it) for the
    136  * abort mechanisms to work properly.
    137  */
    138 static int usb_stor_msg_common(struct us_data *us, int timeout)
    139 {
    140         struct completion urb_done;
    141         struct timer_list to_timer;
    142         int status;
    143
    144         /* don't submit URBs during abort/disconnect processing */
    145         if (us->flags & ABORTING_OR_DISCONNECTING)
    146                 return -EIO;
    147
    148         /* set up data structures for the wakeup system */
    149         init_completion(&urb_done);
    150
    151         /* fill the common fields in the URB */
    152         us->current_urb->context = &urb_done;
    153         us->current_urb->actual_length = 0;
    154         us->current_urb->error_count = 0;
    155         us->current_urb->status = 0;
    156
    157         /* we assume that if transfer_buffer isn't us->iobuf then it
    158          * hasn't been mapped for DMA.  Yes, this is clunky, but it's
    159          * easier than always having the caller tell us whether the
    160          * transfer buffer has already been mapped. */
    161         us->current_urb->transfer_flags =
    162                         URB_ASYNC_UNLINK | URB_NO_SETUP_DMA_MAP;
    163         if (us->current_urb->transfer_buffer == us->iobuf)
    164                 us->current_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
    165         us->current_urb->transfer_dma = us->iobuf_dma;
    166         us->current_urb->setup_dma = us->cr_dma;
    167
    168         /* submit the URB */
    169         status = usb_submit_urb(us->current_urb, GFP_NOIO);
    170         if (status) {
    171                 /* something went wrong */
    172                 return status;
    173         }
    174
    175         /* since the URB has been submitted successfully, it's now okay
    176          * to cancel it */
    177         set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
    178
    179         /* did an abort/disconnect occur during the submission? */
    180         if (us->flags & ABORTING_OR_DISCONNECTING) {
    181
    182                 /* cancel the URB, if it hasn't been cancelled already */
    183                 if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
    184                         US_DEBUGP("-- cancelling URB/n");
    185                         usb_unlink_urb(us->current_urb);
    186                 }
    187         }
    188
    189         /* submit the timeout timer, if a timeout was requested */
    190         if (timeout > 0) {
    191                 init_timer(&to_timer);
    192                 to_timer.expires = jiffies + timeout;
    193                 to_timer.function = timeout_handler;
    194                 to_timer.data = (unsigned long) us;
    195                 add_timer(&to_timer);
    196         }
    197
    198         /* wait for the completion of the URB */
    199         wait_for_completion(&urb_done);
    200         clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
    201
    202         /* clean up the timeout timer */
    203         if (timeout > 0)
    204                 del_timer_sync(&to_timer);
    205
    206         /* return the URB status */
    207         return us->current_urb->status;
    208 }

好了,代码贴完了,现在让我们一点一点去认识这段代码.记住我们最终就是为了看清楚usb_stor_Bulk_max_lun()这个函数究竟是怎么获得max lun.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值