转载于: http://www.voidcn.com/blog/u013388374/article/p-3350460.html
——————/USB摄像头驱动
1、分配usb_driver结构体
2、设置
probe:
2.1、分配video_device:video_device_alloc
2.2、设置
.fops
.ioctl_ops若使用内核提供缓冲区操作函数,还需构造videobuf_queue_ops
2.3、注册video_register_device
3、注册usb_register
——————/uvc_driver.c
uvc_init
usb_register //struct usb_driver
uvc_probe
uvc_register_video
vdev = video_device_alloc();
vdev->fops = &uvc_fops;
vdev->release = video_device_release;
video_register_device
const struct v4l2_file_operations uvc_fops = {
.open = uvc_v4l2_open,
.ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
…...
};
——————/USB Video Camera Topology
每个usb摄像头都含一VC接口,一或多个VS接口(c930e接口0 vc、1 vs、2 ac、3 as)
VC内部抽象出Unit、terminal俩概念,SU即select unit,PU即process unit(亮度、白平衡等控制),IT即input terminal,OT即output terminal,CT即camera terminal
Video functions are addressed through(是通过) their video interfaces. Each video function has a single VideoControl (VC) interface and can have several VideoStreaming (VS) interfaces. The VideoControl (VC) interface is used to access the device controls of the function whereas the VideoStreaming (VS) interfaces are used to transport data streams into and out of the function.
The Input Terminal (IT) is used as an interface between the video function’s "outside world" and other Units inside the video function.
The Camera Terminal (CT) controls mechanical (or equivalent digital) features of the device component that transmits the video stream.(常用usb摄像头只有IT,无CT,p24)
除此之外,还有EU(Encoding Unit)、XU(Extension Unit)等
——————/分析调用过程
open
uvc_v4l2_open //一些基本设置
ioctl
uvc_v4l2_ioctl
video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
uvc_v4l2_do_ioctl (struct file *file, unsigned int cmd, void *arg)
switch (cmd)
case VIDIOC_QUERYCAP
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE| V4L2_CAP_STREAMING;
//根据video->streaming->type设置cap->capabilities
//streaming即VS,type在设备枚举时分析描述符设置的
case VIDIOC_ENUM_FMT
if (fmt->type != video->streaming->type ||fmt->index >= video->streaming->nformats)
return -EINVAL;
format = &video->streaming->format[fmt->index];
//format数组在设备被枚举时设置
case VIDIOC_G_FMT
uvc_v4l2_get_format(struct uvc_video_device*video,struct v4l2_format*fmt)
struct uvc_format *format = video->streaming->cur_format;
struct uvc_frame *frame = video->streaming->cur_frame;
//USB摄像头支持多种format,每种format下有多种frame
fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth;
fmt->fmt.pix.height = frame->wHeight;
case VIDIOC_TRY_FMT
uvc_v4l2_try_format
/* Check if the hardware supports the requested format. */
for (i = 0; i < video->streaming->nformats; ++i)
{
format = &video->streaming->format[i];
if (format->fcc == fmt->fmt.pix.pixelformat)
break;
} //与format数组内容比较
// Find the closest image size.
//以上均没发起USB操作,仅与数组内容比较
case VIDIOC_S_FMT:
uvc_v4l2_set_format(video, arg);
uvc_v4l2_try_format
video->streaming->cur_format = format;
video->streaming->cur_frame = frame;
//仅将参数保存起来,未发送至硬件
case VIDIOC_REQBUFS:
struct v4l2_requestbuffers *rb = arg;
unsigned int bufsize =video->streaming->ctrl.dwMaxVideoFrameSize;
ret = uvc_alloc_buffers(&video->queue, rb->count, bufsize);
/* Decrement the number of buffers until allocation succeeds. */
for (; nbuffers > 0; --nbuffers)
{
mem = vmalloc_32(nbuffers * bufsize);
if (mem != NULL)
break;
}
case VIDIOC_QUERYBUF:
struct v4l2_buffer *buf = arg;
uvc_query_buffer(&video->queue, buf);
__uvc_query_buffer(struct uvc_buffer *buf,struct v4l2_buffer *v4l2_buf)
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);
Mmap
uvc_v4l2_mmap
case VIDIOC_QBUF:
uvc_queue_buffer(struct uvc_video_queue *queue,
list_add_tail(&buf->stream, &queue->mainqueue);
list_add_tail(&buf->queue, &queue->irqqueue);
case VIDIOC_STREAMON:
uvc_video_enable(video, 1) //(struct uvc_video_device*video, int enable)
//把所设置参数发给硬件,然后启动摄像头
/* Commit the streaming parameters. */
uvc_commit_video
uvc_set_video_ctrl
__u8 *data;
__u16 size;
size = video->dev->uvc_version >= 0x0110 ? 34 : 26;
data = kzalloc(size, GFP_KERNEL);
data[2] = ctrl->bFormatIndex; /选择格式、分辨率
data[3] = ctrl->bFrameIndex; //构造数据,没涉及VC
__uvc_query_ctrl(video->dev(哪一个设备), SET_CUR, 0,
video->streaming->intfnum(哪一个接口:VS),……);
usb_control_msg //调用最底层函数发
// Initialize isochronous/bulk URBs and allocate transfer buffers.
uvc_init_video
uvc_init_video_isoc
uvc_alloc_urb_buffers
usb_alloc_urb
urb->complete = uvc_video_complete;
//当接收到urb后所调用的函数
video->decode(urb, video, buf);
//decode在uvc_video.c被初始化
若为实时端点uvc_video_decode_isight
uvc_queue_next_buffer
wake_up(&buf->wait);
若为批量端点uvc_video_decode_bulk
uvc_queue_next_buffer
wake_up(&buf->wait);
uvc_init_video_bulk
// Submit the URBs
usb_submit_urb //启动传输
poll (poll返回,说明已经有数据)
uvc_v4l2_poll
uvc_queue_poll
poll_wait(file, &buf->wait, wait);
case VIDIOC_DQBUF:
uvc_dequeue_buffer
list_del(&buf->stream);
case VIDIOC_STREAMOFF:
uvc_video_enable(video, 0); //与streamon调同一函数,参数异
uvc_uninit_video
usb_kill_urb(urb);
usb_free_urb(urb);
APP调用VIDIOC_QBUF将buf放入队列,后VIDIOC_STREAMON启动传输,接着调用poll查询数据是否已就绪,无数据导致poll_wait休眠等待,当驱动获得数据后,urb(USB request block)的complete函数被调用,最终调用wake_up
——————/以上分析仅涉及VS,下为亮度设置:
case VIDIOC_S_CTRL:
uvc_ctrl_set //设置
uvc_ctrl_commit //向VC interface提交
__uvc_ctrl_commit
uvc_ctrl_commit_entity
uvc_query_ctrl(dev(哪一设备),SET_CUR, ctrl->entity->id(哪一unit/terminal),dev->intfnum(哪一接口:VC接口),……)
——————/总结: 1、UVC设备有2个interface: VC、VS 2、VC用于控制,如设置亮度,内部有多个Unit/Terminal(程序里Unit/Terminal称为entity) 3、VS用于获得视频数据,也可选择fromat/frame(可有多种format, 一种format可支持多种frame, frame表分辨率等信息) 4、UVC驱动重点: 描述符的分析 属性的控制:通过VC设置 格式的选择:通过VS设置 数据的获得:通过VS的URB包