25.设备的生命线(六)
现在来讲usb_submit_urb函数,这是一个有几百行的函数。
220 int usb_submit_urb(struct urb *urb, gfp_t mem_flags) 221 { 222 int pipe, temp, max; 223 struct usb_device *dev; 224 int is_out; 225 226 if (!urb || urb->hcpriv || !urb->complete) 227 return -EINVAL; 228 if (!(dev = urb->dev) || 229 (dev->state < USB_STATE_DEFAULT) || 230 (!dev->bus) || (dev->devnum <= 0)) 231 return -ENODEV; 232 if (dev->bus->controller->power.power_state.event != PM_EVENT_ON 233 || dev->state == USB_STATE_SUSPENDED) 234 return -EHOSTUNREACH; 235 236 urb->status = -EINPROGRESS; 237 urb->actual_length = 0; 238 239 /* Lots of sanity checks, so HCDs can rely on clean data 240 * and don't need to duplicate tests 241 */ 242 pipe = urb->pipe; 243 temp = usb_pipetype(pipe); 244 is_out = usb_pipeout(pipe); 245 246 if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED) 247 return -ENODEV; 248 249 /* FIXME there should be a sharable lock protecting us against 250 * config/altsetting changes and disconnects, kicking in here. 251 * (here == before maxpacket, and eventually endpoint type, 252 * checks get made.) 253 */ 254 255 max = usb_maxpacket(dev, pipe, is_out); 256 if (max <= 0) { 257 dev_dbg(&dev->dev, 258 "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n", 259 usb_pipeendpoint(pipe), is_out ? "out" : "in", 260 __FUNCTION__, max); 261 return -EMSGSIZE; 262 } 263 264 /* periodic transfers limit size per frame/uframe, 265 * but drivers only control those sizes for ISO. 266 * while we're checking, initialize return status. 267 */ 268 if (temp == PIPE_ISOCHRONOUS) { 269 int n, len; 270 271 /* "high bandwidth" mode, 1-3 packets/uframe? */ 272 if (dev->speed == USB_SPEED_HIGH) { 273 int mult = 1 + ((max >> 11) & 0x03); 274 max &= 0x07ff; 275 max *= mult; 276 } 277 278 if (urb->number_of_packets <= 0) 279 return -EINVAL; 280 for (n = 0; n < urb->number_of_packets; n++) { 281 len = urb->iso_frame_desc[n].length; 282 if (len < 0 || len > max) 283 return -EMSGSIZE; 284 urb->iso_frame_desc[n].status = -EXDEV; 285 urb->iso_frame_desc[n].actual_length = 0; 286 } 287 } 288 289 /* the I/O buffer must be mapped/unmapped, except when length=0 */ 290 if (urb->transfer_buffer_length < 0) 291 return -EMSGSIZE; 292 293 #ifdef DEBUG 294 /* stuff that drivers shouldn't do, but which shouldn't 295 * cause proble ms in HCDs if they get it wrong. 296 */ 297 { 298 unsigned int orig_flags = urb->transfer_flags; 299 unsigned int allowed; 300 301 /* enforce simple/standard policy */ 302 allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | 303 URB_NO_INTERRUPT); 304 switch (temp) { 305 case PIPE_BULK: 306 if (is_out) 307 allowed |= URB_ZERO_PACKET; 308 /* FALLTHROUGH */ 309 case PIPE_CONTROL: 310 allowed |= URB_NO_FSBR; /* only affects UHCI */ 311 /* FALLTHROUGH */ 312 default: /* all non-iso endpoints */ 313 if (!is_out) 314 allowed |= URB_SHORT_NOT_OK; 315 break; 316 case PIPE_ISOCHRONOUS: 317 allowed |= URB_ISO_ASAP; 318 break; 319 } 320 urb->transfer_flags &= allowed; 321 322 /* fail if submitter gave bogus flags */ 323 if (urb->transfer_flags != orig_flags) { 324 err("BOGUS urb flags, %x --> %x", 325 orig_flags, urb->transfer_flags); 326 return -EINVAL; 327 } 328 } 329 #endif 330 /* 331 * Force periodic transfer intervals to be legal values that are 332 * a power of two (so HCDs don't need to). 333 * 334 * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC 335 * supports different values... this uses EHCI/UHCI defaults (and 336 * EHCI can use smaller non-default values). 337 */ 338 switch (temp) { 339 case PIPE_ISOCHRONOUS: 340 case PIPE_INTERRUPT: 341 /* too small? */ 342 if (urb->interval <= 0) 343 return -EINVAL; 344 /* too big? */ 345 switch (dev->speed) { 346 case USB_SPEED_HIGH: /* units are microframes */ 347 // NOTE usb handles 2^15 348 if (urb->interval > (1024 * 8)) 349 urb->interval = 1024 * 8; 350 temp = 1024 * 8; 351 break; 352 case USB_SPEED_FULL: /* units are frames/ msec */ 353 case USB_SPEED_LOW: 354 if (temp == PIPE_INTERRUPT) { 355 if (urb->interval > 255) 356 return -EINVAL; 357 // NOTE ohci only handles up to 32 358 temp = 128; 359 } else { 360 if (urb->interval > 1024) 361 urb->interval = 1024; 362 // NOTE usb and ohci handle up to 2^15 363 temp = 1024; 364 } 365 break; 366 default: 367 return -EINVAL; 368 } 369 /* power of two? */ 370 while (temp > urb->interval) 371 temp >>= 1; 372 urb->interval = temp; 373 } 374 375 return usb_hcd_submit_urb(urb, mem_flags); 376 }
这个函数虽然很长,目标却很简单,就是对urb做些前期处理之后扔给HCD。
226行,一些有关存在性的判断,这个函数在开始时就要履行常规的检验,urb为空,都没有初始化是不可以提交给Core的,Core很生气,后果很严重,hcpriv本来说好了留给HCD用的,自己不能偷偷先用了,HCD很生气,后果也会很严重,complete,每个urb结束了都必须得调用一次complete代表的函数。
228行,226行是对urb本身的检验,这里是对urb的目的地USB设备的检验。要想让设备回应,它起码得达到Default状态。
设备编号devnum的值肯定是不能为负的了,那为什么为0也不行呢?Token包的地址域里有7位是表示设备地址的,也就是说总共可以有128个地址来分配给设备,但是其中0号地址是被保留作为默认地址用的,任何一个设备处于Default状态还没有进入Address状态时都需要通过这个默认地址来响应主机的请求,所以0号地址不能分配给任何一个设备,Hub为设备选择一个地址时,只有选择到一个大于0的地址,设备的生命线才会继续,因此说这里的devnum的值是不可能也不应该为0的。
因为要设置设备的地址,让设备进入Address状态,所以针对SET_ADDRESS请求再查看这个devnum。主机向设备发送SET_ADDRESS请求时,如果设备处于Default状态,就是它现在的状态,指定一个非0值时,设备将进入Adress状态;指定0值时,设备仍然会处于Default状态。所以说这里的devnum也是不能为0的。如果设备已经处于Adress状态,指定一个非0值时,设备仍然会处于Address状态,只是将使用新分配的地址,一个设备只能占用一个地址,它是分配的,如果指定了一个0值,则设备将离开Address状态退回到Default状态。
232行,power,power_state,event,还有PM_EVENT_ON都是电源管理核心里的内容,这里的目的是判断设备所在的那条总线的主机控制器有没有挂起,然后再判断设备本身是不是处于Suspended状态。
236行,常规检查都做完了,Core和HCD已经认同了这个urb,就将它的状态设置为-EINPROGRESS,表示从现在开始urb的控制权就在Core和HCD手里了,在驱动那里看不到这个状态。
237行,这时还没开始传输,实际传输的数据长度当然为0了,这里进行初始化,也是为了防止以后哪里出错返回了,在驱动里可以检查。
242行,这几行获得管道的类型及方向。
246行,在设备进入Configured状态之前,主机只能使用控制传输,通过默认管道,也就是管道0来和设备进行交流。
255行,获得端点的wMaxPacketSize,看一看include/linux/usb.h中定义的这个函数:
1458 static inline __u16 1459 usb_maxpacket(struct usb_device *udev, int pipe, int is_out) 1460 { 1461 struct usb_host_endpoint *ep; 1462 unsigned epnum = usb_pipeendpoint(pipe); 1463 1464 if (is_out) { 1465 WARN_ON(usb_pipein(pipe)); 1466 ep = udev->ep_out[epnum]; 1467 } else { 1468 WARN_ON(usb_pipeout(pipe)); 1469 ep = udev->ep_in[epnum]; 1470 } 1471 if (!ep) 1472 return 0; 1473 1474 /* NOTE: only 0x07ff bits are for packet size... */ 1475 return le16_to_cpu(ep->desc.wMaxPacketSize); 1476 }
这个函数是很简单的。要根据现有的信息获得一个端点的wMaxPacketSize当然是必须得获得该端点的描述符,我们知道每个struct usb_device结构体里都有两个数组:ep_out和ep_in,它们保存了各个端点对应的struct usb_host_endpoint结构体,只要知道该端点对应了这两个数组里的哪个元素就可以获得它的描述符了,这就需要知道该端点的端点号和方向,而端点的方向就是管道的方向,端点号也保存在pipe里。
你是不是会担心ep_out或ep_in数组都还空着,或者说没有保存对应的端点信息?不用担心它还是空的,即使是现在设备还刚从Powered走到Default,连Address都没有,但是在使用usb_alloc_dev构造这个设备的struct usb_device时,就把它里面端点0的struct usb_host_endpoint结构体ep0指定给ep_out[0]和ep_in[0]了,而且后来还对ep0的wMaxPacketSize指定了值。不过如果真的没有从它们里面找到想要的端点的信息,那肯定就是哪里出错了,指定了错误的端点号,或其他什么原因,也就不用再继续走下去了。
268行,如果是等时传输就要进行一些特别的处理。272行到276行这几行涉及高速、高带宽端点(high speed,high bandwidth endpoint)。前面提到interval时,说过每一帧或微帧最多只能有一次等时传输,完成一次等时transaction,这么说主要是因为还没遇到高速高带宽的等时端点。高速高带宽等时端点每个微帧可以进行2次到3次等时transaction,它和一般等时端点的主要区别也在这里,没必要专门为它设置个描述符类型,端点描述符wMaxPacketSize字段的bit 11~ bit 12就是用来指定可以额外有几次等时transaction的,00表示没有额外的transaction,01表示额外有1次,10表示额外有2次,11被保留。wMaxPacketSize字段的前10位就是实际的端点每次能够处理的最大字节数。所以这几行意思就是如果是高速等时端点,获得它允许的额外等时transaction次数,和每次能够处理的最大字节数,再将它们相乘就得出了该等时端点每个微帧的所能传输的最大字节数。
278行,number_of_packets不大于0就表示这个等时urb没有指定任何一次等时传输,可以直接返回了。
280行到286行,对等时urb里指定的各次等时传输分别进行处理。如果它们预期传输的数据长度比上面算出来的max值还要大,则返回。然后将它们实际传输的数据长度先置为0,状态都先初始化为-EXDEV,表示这次等时传输仅仅部分完成了,因为走到这里时传输都还没开始。
290行,transfer_buffer_length长度不能小于0,等于0倒是可以的,毕竟不是什么时候都是有数据要传的。
293行,见到#ifdef DEBUG我们都应该很高兴,这意味着一直到下面对应的#endif之间的代码都是调试时用的,对整体函数的作用无关痛痒。
338行,temp是上面计算出来的管道类型,那下面的各个case肯定是针对四种传输类型的了。不过可以发现,这里只“case”了等时传输和中断传输两种周期性的传输类型,因为是关于interval的处理,所以就没有控制传输和批量传输了。
342行,这里保证等时和中断urb的interval值必须是大于0的,不然主机那边看不懂这是什么意思。
345行,这里的switch根据目的设备的速度去“case”,设备速度有三种,case也有三个。前面已经说过,不同的速度,urb->interval可以取不同的范围,不过你可能会发现那时说的最大值要比这里的限制要大一些,这是因为协议归协议,实现归实现。比如,对于UHCI来说,中断传输的interval值不能比128更大,而协议规定的最大值为255。那么现在的问题是,temp又是做什么用的?要注意urb->interval的单位是帧或者微帧,temp只是为了调整它的值为2的次幂,这点从370行就可以看出来。
375行,将urb交给HCD,然后就进入HCD了。
本来usb_submit_urb函数到此应该结束了,但是它对于写驱动的来说太重要了,驱动里做的所有铺垫就是为了使用usb_submit_urb提交一个合适的urb给设备,满怀期待地等待着设备回馈需要的信息,然后才有接下来的处理,不然USB驱动只是一纸空谈毫无用处。
第一还是要再次强调,在调用usb_submit_urb提交你的urb之前,一定必须不得不要对它正确初始化,对于控制/中断/批量传输,Core都提供了usb_fill_control_urb的几个孪生兄弟供你初始化使用,对于等时传输要自己手工一步一步小心翼翼地对urb的相关元素逐个赋值。urb决定了整个USB驱动能否顺利运转。
第二,对于驱动来说,usb_submit_urb是异步的,也就是说不用等传输完全完成就返回了,只要usb_submit_urb的返回值表示为0,就表示已经提交成功了,urb已经被Core和HCD认可了,接下来Core和HCD怎么处理就是它们的事了。
只要你提交成功了,不管是中间出了差错还是顺利完成,你指定的结束处理函数总是会调用,只有到这个时候,你才能够重新拿到urb的控制权,检查它是不是出错了,需要不需要释放或者是重新提交。第三,什么时候需要在结束处理函数中重新提交这个urb?其实,我更想问的是对于中断/等时传输,是怎么实现让主机按一定周期去访问端点的?端点的描述符里已经指定了这个间隔时间,urb里也有interval描述了这个间隔周期。可是urb一次只完成一次传输,即使等时传输也只完成有限次的传输,然后就在结束处理函数中返回了,urb的控制权就完全属于驱动了,接下来的周期访问是怎么做到的?难道脱离urb后主机自己就去自动与端点通信了?即使是这样了,那通信的数据又在哪里,又怎么去得到这些数据?
事实上,第一次提交一个中断或等时的urb时,HCD会根据interval判断自己是否能够满足你的需要,如果不能够安排足够的带宽来完成这种周期性的传输,它是不可能会批准请求的,如果它估计觉得可以满足,就会保留足够的带宽。但是这并不是就表明万事大吉了,HCD是保留带宽了,可是驱动得保证在对应端点要处理的urb队列里总是有urb,不能是空的,否则这个保留的带宽就会被“cancel”掉。
那么对于中断/等时传输,如何保证对应端点的urb队列里总是会有urb?这就回到最开始的问题了。驱动需要在结束处理函数中重新初始化和提交刚刚完成的urb,提醒这个时候你是不能够修改interval的值,否则等待你的只能是错误信息。中断传输的例子可以去看一看触摸屏驱动,等时传输的例子可以去看一看摄像头驱动,看一看它们在结束处理函数中都做了些什么,你就知道了。
第四,对于控制/批量/中断传输,实际上很多时候你可以不用创建urb,不用对它初始化,不用调用usb_submit_urb来提交,USB Core将这个过程分别封装在了usb_control_ msg、usb_bulk_ msg和usb_interrupt_ msg这三个函数中,不同的是它们的实现是同步的,会去等待传输完全结束。咱们就是从usb_control_ msg走过来的,所以这里只查看另外两个,它们都定义在drivers/usb/core/message.c里。
169 int usb_interrupt_ msg(struct usb_device *usb_dev, unsigned int pipe, 170 void *data, int len, int *actual_length, int timeout) 171 { 172 return usb_bulk_ msg(usb_dev, pipe, data, len, actual_length, timeout); 173 }
usb_interrupt_ msg全部都借助usb_bulk_ msg去完成了。
207 int usb_bulk_ msg(struct usb_device *usb_dev, unsigned int pipe, 208 void *data, int len, int *actual_length, int timeout) 209 { 210 struct urb *urb; 211 struct usb_host_endpoint *ep; 212 213 ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out) 214 [usb_pipeendpoint(pipe)]; 215 if (!ep || len < 0) 216 return -EINVAL; 217 218 urb = usb_alloc_urb(0, GFP_KERNEL); 219 if (!urb) 220 return -ENOMEM; 221 222 if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == 223 USB_ENDPOINT_XFER_INT) { 224 pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); 225 usb_fill_int_urb(urb, usb_dev, pipe, data, len, 226 usb_api_blocking_completion, NULL, 227 ep->desc.bInterval); 228 } else 229 usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, 230 usb_api_blocking_completion, NULL); 231 232 return usb_start_wait_urb(urb, timeout, actual_length); 233 }
首先根据指定的pipe获得端点的方向和端点号,然后从设备struct usb_device结构体的ep_in或ep_out数组里得到端点对应的struct usb_host_endpoint结构体,接着调用usb_alloc_urb创建urb。
因为这个函数可能是从usb_interrupt_ msg调用过来的,所以接下来要根据端点描述符的bmAttributes字段获取传输的类型,判断究竟是中断传输还是批量传输,如果是中断传输的话还要修改pipe的类型,防止万一被其他函数直接调用usb_bulk_ msg来完成中断传输。
不管是中断传输还是批量传输,都要调用usb_fill_xxx_urb函数来初始化,最后,和usb_control_ msg一样,调用usb_start_wait_urb函数。