【转】Linux那些事儿 之 戏说USB(30)设备的生命线(九)

来源:互联网 发布:js h5拼图游戏源码 编辑:程序博客网 时间:2024/05/18 01:07

聊完了struct usb_hcd和struct usb_bus,算是已经向HCD片儿区的老大们拜过山头了,接下来就该看看usb_submit_urb()最后的那个遗留问题 usb_hcd_submit_urb()了,要有心理准备,也是个一百多行的狠角色。现在内核里有个很不好的现象,设计结构比复杂,写函数比长。像一个 中介语重心长的说:我承认的确房屋中介有不好的现象,收看房费,收差价,很是让人生气,作为业内人士我感到很心酸,但是还是有好的啊。不管怎地苦的都是我 们,如果你缺少动力往下看,就去看一遍福布斯美国富翁排行榜,如果上面没有你的名字,你就继续往下看,这是勉励俺的,也拿来与你共勉。

916 /* may be called in any context with a valid urb->dev usecount
917 * caller surrenders "ownership" of urb
918 * expects usb_submit_urb() to have sanity checked and conditioned all
919 * inputs in the urb
920 */
921 int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
922 {
923         int                     status;
924         struct usb_hcd          *hcd = bus_to_hcd(urb->dev->bus);
925         struct usb_host_endpoint *ep;
926         unsigned long           flags;
927
928         if (!hcd)
929                 return -ENODEV;
930
931         usbmon_urb_submit(&hcd->self, urb);
932
933         /*
934          * Atomically queue the urb, first to our records, then to the HCD.
935          * Access to urb->status is controlled by urb->lock ... changes on
936          * i/o completion (normal or fault) or unlinking.
937          */
938
939         // FIXME: verify that quiescing hc works right (RH cleans up)
940
941         spin_lock_irqsave (&hcd_data_lock, flags);
942         ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
943                         [usb_pipeendpoint(urb->pipe)];
944         if (unlikely (!ep))
945                 status = -ENOENT;
946         else if (unlikely (urb->reject))
947                 status = -EPERM;
948         else switch (hcd->state) {
949         case HC_STATE_RUNNING:
950         case HC_STATE_RESUMING:
951 doit:
952                 list_add_tail (&urb->urb_list, &ep->urb_list);
953                 status = 0;
954                 break;
955         case HC_STATE_SUSPENDED:
956                 /* HC upstream links (register access, wakeup signaling) can work
957                  * even when the downstream links (and DMA etc) are quiesced; let
958                  * usbcore talk to the root hub.
959                  */
960                 if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
961                                 && urb->dev->parent == NULL)
962                         goto doit;
963                 /* FALL THROUGH */
964         default:
965                 status = -ESHUTDOWN;
966                 break;
967         }
968         spin_unlock_irqrestore (&hcd_data_lock, flags);
969         if (status) {
970                 INIT_LIST_HEAD (&urb->urb_list);
971                 usbmon_urb_submit_error(&hcd->self, urb, status);
972                 return status;
973         }
974
975         /* increment urb's reference count as part of giving it to the HCD
976          * (which now controls it). HCD guarantees that it either returns
977          * an error or calls giveback(), but not both.
978          */
979         urb = usb_get_urb (urb);
980         atomic_inc (&urb->use_count);
981
982         if (urb->dev == hcd->self.root_hub) {
983                 /* NOTE: requirement on hub callers (usbfs and the hub
984                  * driver, for now) that URBs' urb->transfer_buffer be
985                  * valid and usb_buffer_{sync,unmap}() not be needed, since
986                  * they could clobber root hub response data.
987                  */
988                 status = rh_urb_enqueue (hcd, urb);
989                 goto done;
990         }
991
992         /* lower level hcd code should use *_dma exclusively,
993          * unless it uses pio or talks to another transport.
994          */
995         if (hcd->self.uses_dma) {
996                 if (usb_pipecontrol (urb->pipe)
997                         && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
998                         urb->setup_dma = dma_map_single (
999                                         hcd->self.controller,
1000                                         urb->setup_packet,
1001                                         sizeof (struct usb_ctrlrequest),
1002                                         DMA_TO_DEVICE);
1003                 if (urb->transfer_buffer_length != 0
1004                         && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
1005                         urb->transfer_dma = dma_map_single (
1006                                         hcd->self.controller,
1007                                         urb->transfer_buffer,
1008                                         urb->transfer_buffer_length,
1009                                         usb_pipein (urb->pipe)
1010                                             ? DMA_FROM_DEVICE
1011                                             : DMA_TO_DEVICE);
1012         }
1013
1014         status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
1015 done:
1016         if (unlikely (status)) {
1017                 urb_unlink (urb);
1018                 atomic_dec (&urb->use_count);
1019                 if (urb->reject)
1020                         wake_up (&usb_kill_urb_queue);
1021                 usbmon_urb_submit_error(&hcd->self, urb, status);
1022                 usb_put_urb (urb);
1023         }
1024         return status;
1025 }
usb_hcd_submit_urb 是hcd.c里的,目标也很明确,就是将提交过来的urb指派给合适的主机控制器驱动程序。core目录下面以hcd打头的几个文件严格来说不能算是 HCD,只能算HCDI,即主机控制器驱动的接口层,用来衔接具体的主机控制器驱动和usb core的。
924 行,bus_to_hcd在哪里提到过一下,是用来获得struct usb_bus结构体对应的struct usb_hcd结构体,urb要去的那个设备所在的总线是在设备生命线的开头儿就初始化好了的,忘了可以再蓦然回首一下。bus_to_hcd还有个兄弟 hcd_to_bus,都在hcd.h里定义
131 static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
132 {
133         return &hcd->self;
134 }
135
136 static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
137 {
138         return container_of(bus, struct usb_hcd, self);
139 }
这俩函数傻强都能看懂,继续看928行,也是大多数函数开头儿必备的常规检验,如果usb_hcd都还是空的,那就别开国际玩笑了,返回吧。
931行,usbmon_urb_submit就是与前面Greg孕育出来的usb Monitor有关的,如果你编译内核的时候没有配置上CONFIG_USB_MON,它就啥也不是,一个空函数,一具空壳。
941行,去获得一把锁,这把锁在hcd.c的开头儿就已经初始化好了,所以说是把全局锁
102 /* used when updating hcd data */
103 static DEFINE_SPINLOCK(hcd_data_lock);
前 边儿多次遇到过自旋锁,不过一直没功夫说它,现在就简单介绍一下。它和信号量,还有前面提到的completion一样都是linux里用来进行代码同步 的,为什么要进行同步?你要知道在linux这个庞大负责的世界里,不是只有你一个人在战斗,可能同时有多个线程,多杆枪在战斗,那么只要他们互相之间有 一定的共享,就必须要保证一个人操作这个共享的时候让其它人知道,这么说吧,你和另外一个人带领两只队伍去打土匪窝,结果你方武力值,智力值比较高,先占 领了山头儿,你得插把旗子表示你已经占领了,让友军不要再打了,过来享受胜利果实吧,里边土匪太太,美酒美食一堆一堆的,如果你什么都不说,没插旗子也没 其它什么暗号表示一下,只顾自个儿享受了,那边儿正打着过瘾谁知道在匪窝儿里的是你还是土匪啊。所以说同步是多重要啊,保持共享代码的状态一致是多么重要 啊。
自 旋锁身为同步机制的一种,自然也有它独特的本事,它可以用在中断上下文或者说原子上下文使用。上下文就是你代码运行的环境,linux的这个环境使用二分 法可以分成两种,能睡觉的环境和不能睡觉的环境。像信号量和completion就只能用在可以睡觉的环境,而自旋锁就用在不能睡觉的环境里。而咱们的 usb_submit_urb还有usb_hcd_submit_urb必须得在两种环境里都能够使用,所以使用的是自旋锁,那在什么时候都不能睡觉了还 有心情去调用它们那?想想urb的那个结束处理函数,它就是不能睡觉的,但它里面必须得能够重新提交urb。
那 再说说hcd_data_lock这把锁都是用来保护些什么的,为什么要使用它?主机控制器的struct usb_hcd结构体在它的驱动里早就初始化好了,就那么一个,但同一时刻是可能有多个urb向同一主机控制器申请进行传输,可能有多个地方都希望访问它 里面的内容的,比如948行的state元素,显然就要同步了,hcd_data_lock这把锁就是专门用来保护主机控制器的这个结构体的。
942 行,遇到多次也说过多次了,知道了pipe,就可以从struct usb_device里的两个数组ep_in和ep_out里拿出对应端点的struct usb_host_endpoint结构体。写代码的哥们儿也知道咱们说过多次了,就直接把这一堆搞一行里了。
944~973这些行都是做检验的,写个代码真费劲儿,到处都是地雷暗礁,到处都要检验。就好像去年以前还处于公粮时代的时候,那些验粮的,要一关又一关的,发生了多少可歌可泣的故事啊。验粮的都要牙好,写代码看代码的当然都要耐心好了。
944行,显然都走到这一步了,目的端点为空的可能性太小了,所以加上了unlikely。
946行,前面还费了点口舌说过,urb里的这个reject,只有usb_kill_urb有特权修改它,如果走到这里发现它的值大于0了,那就说明哪里调用了usb_kill_urb要终止这次传输,所以就还是返回吧,不过这种可能性比较小,没人无聊到那种地步,总是刚提交就终止,吊主机控制器胃口,所以仍然加上unlikely。
948 行,如果上面那两个检验都通过了,现在就case一下主机控制器的状态,如果为HC_STATE_RUNNING或HC_STATE_RESUMING就 说明主机控制器这边儿没问题,尽管将这个urb往端点的那个urb队列里塞好了,952行就是完成这个的,struct urb那么变态的结构都熬过来了,这行是小case了。如果主机控制器的状态为HC_STATE_SUSPENDED,但它的上行链路能够工作,且这个 urb是送往root hub的,则将其塞到root hub的urb队列里。
然后判断上面几次检验的结果,如果一切正常,则继续往下走,否则就黯然回头吧。
979行,检验都通过了,可以放心的增加urb的引用计数了。
980行,将urb的use_count也增加1,表示urb已经被HCD接受了,正在被处理着。你如果对这两个引用计数什么差别还有疑问,再蓦然回首一下看看说struct urb时讲的。
982行,判断这个urb是不是流向root hub的,如果是,它就走向了root hub的生命线。不过,毕竟你更关注的是你的usb设备,应该很少有机会和欲望直接和root hub交流些什么。
995 行,如果这个主机控制器支持DMA,可你却没有告诉它URB_NO_SETUP_DMA_MAP或URB_NO_TRANSFER_DMA_MAP这两个 标志,它就会认为你在urb里没有提供DMA的缓冲区,就会调用dma_map_single将setup_packet或 transfer_buffer映射为DMA缓冲区。
1014行,终于可以将urb扔给具体的主机控制器驱动程序了,urb可以欢快的尽情呼喊,UHCI,OHCI,EHCI,我来了!
 
下 面的路就让urb去走吧,咱们说到这里也该回头了,经过了这么多事,遇到了这么多人,我始终都不能忘怀自己是从设置设备地址,发送SET_ADDRESS 请求给主机控制器开始,这么一路走过来的,到现在,设备已经可以进入Address状态,这桩心愿已了,该继续看设备的那条生命线了。