目录:
一 USB摄像头驱动整体框架
二 UVC驱动简析
- 2.1 USB摄像头硬件结构简析
- 2.2 分析UVC驱动调用过程
一 USB摄像头驱动整体框架
1.构造一个usb_driver
2.设置
probe:
2.1. 分配video_device:video_device_alloc
2.2. 设置
.fops
.ioctl_ops (里面需要设置11项)
如果要用内核提供的缓冲区操作函数,还需要构造一个videobuf_queue_ops
2.3. 注册: video_register_device
id_table: 表示支持哪些USB设备
3.注册: usb_register
二 UVC驱动简析
UVC: USB Video Class
UVC驱动:drivers\media\video\uvc\
2.1 USB摄像头硬件结构简析
UVC 1.5 Class specification.pdf :
Video functions are addressed through their video interfaces. Each video function has a single VideoControl (VC) interface and can have several VideoStreaming (VS) interfaces. TheVideoControl (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
VC内部抽象出两个基本的模块 Units 和 Terminals,Terminals用于“内外连接”,Units 是VC 内部功能模块,IT用于输入,OT用于输出,SU用于多路选择,PU控制属性。
The Input Terminal (IT) is used as an interface between the video function’s “outside world” and other Units inside the video function.
The Output Terminal (OT) is used as an interface between Units inside the video function and the “outside world”.
The Camera Terminal (CT) controls mechanical (or equivalent digital) features of the device component that transmits the video stream.
The Selector Unit (SU) selects from n input data streams and routes them unaltered to the single output stream. It represents a source selector, capable of selecting among a number of sources. It has an Input Pin for each source stream and a single Output Pin
The Processing Unit (PU) controls image attributes of the video being streamed through it. It has a single input and output pin. It provides support for the following features:
User Controls
Brightness
Hue
Saturation
Sharpness
Gamma
Digital Multiplier (Zoom)
–
VC
Units
SU : Select Units
PU : Process Units
Terminals
IT : Input Terminals
CT : Camera Terminals
OT : Output Terminals
VS
小结:
1 通过VideoControl Interface来控制,
2 通过VideoStreaming Interface来读视频数据,
3 VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度
2.2 分析UVC驱动调用过程:
const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
};
- open:
uvc_v4l2_open
- VIDIOC_QUERYCAP // video->streaming->type 应该是在设备被枚举时分析描述符时设置的
if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING;
else
cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
| V4L2_CAP_STREAMING;
- VIDIOC_ENUM_FMT // format数组应是在设备被枚举时设置的
format = &video->streaming->format[fmt->index];
- VIDIOC_G_FMT
uvc_v4l2_get_format // USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
struct uvc_format *format = video->streaming->cur_format;
struct uvc_frame *frame = video->streaming->cur_frame;
- VIDIOC_TRY_FMT
uvc_v4l2_try_format
/* Check if the hardware supports the requested format. */
/* Find the closest image size. The distance between image sizes is
* the size in pixels of the non-overlapping regions between the
* requested size and the frame-specified size.
*/
- VIDIOC_S_FMT // 只是把参数保存起来,还没有发给USB摄像头
uvc_v4l2_set_format
uvc_v4l2_try_format
video->streaming->cur_format = format;
video->streaming->cur_frame = frame;
- VIDIOC_REQBUFS
uvc_alloc_buffers
for (; nbuffers > 0; --nbuffers) {
mem = vmalloc_32(nbuffers * bufsize);
if (mem != NULL)
break;
- VIDIOC_QUERYBUF
uvc_query_buffer
__uvc_query_buffer
memcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf); // 复制参数
- mmap
uvc_v4l2_mmap
- VIDIOC_QBUF
uvc_queue_buffer
list_add_tail(&buf->stream, &queue->mainqueue);
list_add_tail(&buf->queue, &queue->irqqueue);
- VIDIOC_STREAMON
uvc_video_enable(video, 1) // 把所设置的参数发给硬件,然后启动摄像头
/* Commit the streaming parameters. */
uvc_commit_video
uvc_set_video_ctrl /* 设置格式fromat, frame */
ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,
video->streaming->intfnum /* 哪一个接口: VS */,
probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
uvc_timeout_param);
/* 启动:Initialize isochronous/bulk URBs and allocate transfer buffers. */
uvc_init_video(video, GFP_KERNEL);
uvc_init_video_isoc / uvc_init_video_bulk
urb->complete = uvc_video_complete; (收到数据后此函数被调用,它又调用video->decode(urb, video, buf); ==> uvc_video_decode_isoc/uvc_video_encode_bulk => uvc_queue_next_buffer => wake_up(&buf->wait);)
usb_submit_urb
- poll
uvc_v4l2_poll
uvc_queue_poll
poll_wait(file, &buf->wait, wait); // 休眠等待有数据
- VIDIOC_DQBUF
uvc_dequeue_buffer
list_del(&buf->stream);
- VIDIOC_STREAMOFF
uvc_video_enable(video, 0);
usb_kill_urb(urb);
usb_free_urb(urb);
分析设置亮度过程:
ioctl: VIDIOC_S_CTRL
uvc_ctrl_set
uvc_ctrl_commit
__uvc_ctrl_commit(video, 0);
uvc_ctrl_commit_entity(video->dev, entity, rollback);
ret = uvc_query_ctrl(dev /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id /* 哪一个unit/terminal */,
dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
小结:
1 UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface
2 VideoControl Interface用于控制,比如设置亮度。它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity)可以通过类似的函数来访问:
ret = uvc_query_ctrl(dev /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id /* 哪一个unit/terminal */,
dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info->size);
3 VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format, 一个format支持多种frame, frame用来表示分辨率等信息) 可以通过类似的函数来访问:
ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,
video->streaming->intfnum /* 哪一个接口: VS */,
probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
uvc_timeout_param);
4 我们在设置FORMAT时只是简单的使用video->streaming->format[fmt->index]等数据,这些数据哪来的? 应是设备被枚举时设置的,也就是分析它的描述符时设置的。
5 UVC驱动的重点在于:
描述符的分析
属性的控制: 通过VideoControl Interface来设置
格式的选择:通过VideoStreaming Interface来设置
数据的获得:通过VideoStreaming Interface的URB来获得