如何知道设备控制设备的开流和关流动作

网友投稿 304 2022-11-17

如何知道设备控制设备的开流和关流动作

1.描述符布局

如图为 bulk 传输描述符布局,相对于同步传输,批量传输只有一个可选择的配置,没有备用配置。

VideoControl :无变化

需要修改的地方:

端点描述符:

2. 控制流程

根据USB规范可知,同步传输方式是只要带中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要停止数据的传输,只需要选中不带有同步端点的接口即可。

我们知道,批量传输只有一个可选择的altsetting ,那么如何知道设备控制设备的开流和关流动作呢?

2.1 stream on

使用视频流接口的VS_COMMIT_CONTROL 提交给设备,让其以指定的数据格式进行数据采样。

2.2 stream off

关流操作,通过抓包可以看到,通过发送一个clear_halt 请求,来中断流的操作。

2.3 代码分析

drivers/media/usb/uvc/uvc_queue.c

开流操作:uvc_start_streaming

关流操作:uvc_stop_streaming

staticvoiduvc_stop_streaming(structvb2_queue*vq){structuvc_video_queue*queue=vb2_get_drv_priv(vq);structuvc_streaming*stream=uvc_queue_to_stream(queue);unsignedlongflags;uvc_video_enable(stream,0);spin_lock_irqsave(&queue->irqlock,flags);uvc_queue_return_buffers(queue,UVC_BUF_STATE_ERROR);spin_unlock_irqrestore(&queue->irqlock,flags);}

重点关注:uvc_video_enable

/**Enableordisablethevideostream.*/intuvc_video_enable(structuvc_streaming*stream,intenable){intret;if(!enable){uvc_uninit_video(stream,1);if(stream->intf->num_altsetting>1){usb_set_interface(stream->dev->udev,stream->intfnum,0);}else{/*UVCdoesn'tspecifyhowtoinformabulk-baseddevice*whenthevideostreamisstopped.Windowssendsa*CLEAR_FEATURE(HALT)requesttothevideostreaming*bulkendpoint,mimicthesamebehaviour.*/unsignedintepnum=stream->header.bEndpointAddress&USB_ENDPOINT_NUMBER_MASK;unsignedintdir=stream->header.bEndpointAddress&USB_ENDPOINT_DIR_MASK;unsignedintpipe;pipe=usb_sndbulkpipe(stream->dev->udev,epnum)|dir;usb_clear_halt(stream->dev->udev,pipe);}uvc_video_clock_cleanup(stream);return0;}ret=uvc_video_clock_init(stream);if(ret< 0)  return ret; /* Commit the streaming parameters. */ ret = uvc_commit_video(stream, &stream->ctrl);if(ret< 0)  goto error_commit; ret = uvc_init_video(stream, GFP_KERNEL); if (ret < 0)  goto error_video; return 0;error_video: usb_set_interface(stream->dev->udev,stream->intfnum,0);error_commit:uvc_video_clock_cleanup(stream);returnret;}

分析代码可知:

首先判断是否关流操作;

如果是,判断接口的可选配置是否大于1,如果大于1,发送usb_set_interface(intfnum,0) 关流,否则发送usb_clear_halt 请求;

如果是开流操作,发送commit 请求

然后初始化 video

/**Initializeisochronous/bulkURBsandallocatetransferbuffers.*/staticintuvc_init_video(structuvc_streaming*stream,gfp_tgfp_flags){structusb_interface*intf=stream->intf;structusb_host_endpoint*ep;unsignedinti;intret;stream->sequence=-1;stream->last_fid=-1;stream->bulk.header_size=0;stream->bulk.skip_payload=0;stream->bulk.payload_size=0;uvc_video_stats_start(stream);if(intf->num_altsetting>1){structusb_host_endpoint*best_ep=NULL;unsignedintbest_psize=UINT_MAX;unsignedintbandwidth;unsignedintuninitialized_var(altsetting);intintfnum=stream->intfnum;/*Isochronousendpoint,selectthealternatesetting.*/bandwidth=stream->ctrl.dwMaxPayloadTransferSize;if(bandwidth==0){uvc_trace(UVC_TRACE_VIDEO,"Devicerequestednull""bandwidth,defaultingtolowest.");bandwidth=1;}else{uvc_trace(UVC_TRACE_VIDEO,"Devicerequested%u""B/framebandwidth.",bandwidth);}for(i=0;i< intf->num_altsetting;++i){structusb_host_interface*alts;unsignedintpsize;alts=&intf->altsetting[i];ep=uvc_find_endpoint(alts,stream->header.bEndpointAddress);if(ep==NULL)continue;/*Checkifthebandwidthishighenough.*/psize=uvc_endpoint_max_bpi(stream->dev->udev,ep);if(psize>=bandwidth&&psize<= best_psize) {    altsetting = alts->desc.bAlternateSetting;best_psize=psize;best_ep=ep;}}if(best_ep==NULL){uvc_trace(UVC_TRACE_VIDEO,"Nofastenoughaltsetting""forrequestedbandwidth.");return-EIO;}uvc_trace(UVC_TRACE_VIDEO,"Selectingalternatesetting%u""(%uB/framebandwidth).",altsetting,best_psize);ret=usb_set_interface(stream->dev->udev,intfnum,altsetting);if(ret< 0)   return ret;  ret = uvc_init_video_isoc(stream, best_ep, gfp_flags); } else {  /* Bulk endpoint, proceed to URB initialization. */  ep = uvc_find_endpoint(&intf->altsetting[0],stream->header.bEndpointAddress);if(ep==NULL)return-EIO;/*Rejectbrokendescriptors.*/if(usb_endpoint_maxp(&ep->desc)==0)return-EIO;ret=uvc_init_video_bulk(stream,ep,gfp_flags);}if(ret< 0)  return ret; /* Submit the URBs. */ for (i = 0; i < UVC_URBS; ++i) {  ret = usb_submit_urb(stream->urb[i],gfp_flags);if(ret< 0) {   uvc_printk(KERN_ERR, "Failed to submit URB %u "     "(%d).", i, ret);   uvc_uninit_video(stream, 1);   return ret;  } } /* The Logitech C920 temporarily forgets that it should not be adjusting  * Exposure Absolute during init so restore controls to stored values.  */ if (stream->dev->quirks&UVC_QUIRK_RESTORE_CTRLS_ON_INIT)uvc_ctrl_restore_values(stream->dev);return0;}

从这段代码可以看出,如果altsetting 大于1 走同步传输,发送usb_set_interface(intfnum, altsetting) ,选择合适带宽配置。然后初始化同步传输管道。

否则,初始化 同步传输管道,提交传输。

3. 其他注意点

对比同步传输和批量传输我们可以发现,对于uvc 批量传输, 由于没有同步传输类似的多个可选配置,所以没法灵活控制开流关流操作。特别是在linux 平台下,要切换不同的格式和分辨率的时候没有同步传输方便。

故,笔者觉得同步传输适合传固定数据,或者对usb camera 做中转使用比较合适。

对于批量传输如果能充分发送usb 吞吐量,(USB2.0)一个微帧传输13个packet,理论带宽将近50MB/s, 笔者实际测试能达到47MB/s,对于YUYV图像能够极大提高帧率。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:大数据学习笔记-------------------(13)
下一篇:java多线程Synchronized实现可见性原理解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~