190 likes | 297 Views
SNONIX 120 摄像头驱动程序设计. By :刘京 李康年 刘权 陈靖. 主要内容:. USB 摄像头驱动简介 V4L2 简介 v4l2 视频处理的步骤 urb 结构体简介 驱动原理. USB 摄像头驱动. USB 摄像头以其良好的性能和低廉的价格得到广泛应用 但由于摄像头所用芯片的不同,以及传感器的多样性,需对其进行驱动程序的编写. 摄像头驱动的特殊性.
E N D
SNONIX 120摄像头驱动程序设计 By:刘京 李康年 刘权 陈靖
主要内容: • USB摄像头驱动简介 • V4L2简介 • v4l2视频处理的步骤 • urb结构体简介 • 驱动原理
USB摄像头驱动 • USB摄像头以其良好的性能和低廉的价格得到广泛应用 • 但由于摄像头所用芯片的不同,以及传感器的多样性,需对其进行驱动程序的编写
摄像头驱动的特殊性 • 摄像头属于视频类设备。在目前的Linux核心中,视频部分的标准是Video for Linux(简称V4L)。这个标准其实定义了一套接口,内核、驱动、应用程序以这个接口为标准进行交流
V4L2简介 • 一个Linux系统用来处理视频图形的接口。它由一个视频接口 • 标准以及一系列的API组成。
v4l2视频处理的步骤: • 1:打开设备。 • 2:设置设备属性,图形分辨率,亮度。 • 3:协定数据格式。 • 4:协定输入输出方法。 • 5:输入,输出循环。 • 6:关闭设备。
urb结构体简介 • Linux 内核中的USB代码通过一个称为urb(USB 请求块)的东西和所有的USB设备通信。 • urb 被用来以一种异步的方式往/ 从特定的USB 设备上的特定USB端点发送/ 接收数据。重用单个的urb,这取决于驱动程序的需要。设备中的每个端点都可以处理一个urb 队列,所以多个urb可以在队列为空之前发送到同一个端点
urb的生命周期(一) • 由USB 设备驱动程序创建。 • 分配给一个特定USB 设备的特定端点。 • 由USB 设备驱动程序递交到USB 核心。
urb的生命周期(二) • 由USB 核心递交到特定设备的特定USB 主控制器驱动程序。 • 由USB 主控制器驱动程序处理,它从设备进行USB 传送。 • 当urb 结束之后,USB 主控制器驱动程序通知USB设备驱动程序。
static void sn9c120_urb_complete(struct urb *urb) //ok • { • struct sn9c120_device* cam = urb->context; • struct sn9c120_frame_t** f; • size_t imagesize, soflen; • u8 i; • int err = 0; • if (urb->status == -ENOENT) • return;
f = &cam->frame_current; • if (cam->stream == STREAM_INTERRUPT) { • cam->stream = STREAM_OFF; • if ((*f)) • (*f)->state = F_QUEUED; • cam->sof.bytesread = 0; • printk( "Stream interrupted by application\n"); • wake_up(&cam->wait_stream); • } • if (cam->state & DEV_DISCONNECTED) • return; • if (cam->state & DEV_MISCONFIGURED) { • wake_up_interruptible(&cam->wait_frame); • return; • } • if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue)) • goto resubmit_urb;
if (!(*f)) • (*f) = list_entry(cam->inqueue.next, struct sn9c120_frame_t, • frame); • imagesize = (cam->sensor.pix_format.width * • cam->sensor.pix_format.height * • cam->sensor.pix_format.priv) / 8; • if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_JPEG) • imagesize += 589; /* length of jpeg header */ • soflen = sn9c120_sof_length(cam); • for (i = 0; i < urb->number_of_packets; i++) { • unsigned int img, len, status; • void *pos, *sof, *eof; • len = urb->iso_frame_desc[i].actual_length; • status = urb->iso_frame_desc[i].status; • pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer; • if (status) { • printk( "Error in isochronous frame\n"); • (*f)->state = F_ERROR; • cam->sof.bytesread = 0; • continue; • }
redo: • sof = sn9c120_find_sof_header(cam, pos, len); • if (likely(!sof)) { • eof = sn9c120_find_eof_header(cam, pos, len); • if ((*f)->state == F_GRABBING) { • end_of_frame: • img = len; • if (eof) • img = (eof > pos) ? eof - pos - 1 : 0; • if ((*f)->buf.bytesused + img > imagesize) { • u32 b; • b = (*f)->buf.bytesused + img - • imagesize; • img = imagesize - (*f)->buf.bytesused; • printk("Expected EOF not found: video " • "frame cut\n"); • if (eof) • printk( "Exceeded limit: +%u " • "bytes\n", (unsigned)(b)); • }
memcpy((*f)->bufmem + (*f)->buf.bytesused, pos, • img); • if ((*f)->buf.bytesused == 0) • do_gettimeofday(&(*f)->buf.timestamp); • (*f)->buf.bytesused += img; • if ((*f)->buf.bytesused == imagesize || • ((cam->sensor.pix_format.pixelformat == • V4L2_PIX_FMT_SN9C10X || • cam->sensor.pix_format.pixelformat == • V4L2_PIX_FMT_JPEG) && eof)) { • u32 b; • b = (*f)->buf.bytesused; • (*f)->state = F_DONE; • (*f)->buf.sequence= ++cam->frame_count; • spin_lock(&cam->queue_lock); • list_move_tail(&(*f)->frame, • &cam->outqueue); • if (!list_empty(&cam->inqueue)) • (*f) = list_entry( • cam->inqueue.next, • struct sn9c120_frame_t, • frame ); • else • (*f) = NULL; • spin_unlock(&cam->queue_lock);
memcpy(cam->sysfs.frame_header, • cam->sof.header, soflen); • printk( "Video frame captured: %lu " • "bytes\n", (unsigned long)(b)); • if (!(*f)) • goto resubmit_urb; • } else if (eof) { • (*f)->state = F_ERROR; • } • if (sof) /* (1) */ • goto start_of_frame; • } else if (eof) { • printk( "EOF without SOF\n"); • continue; • } else { • printk("Ignoring pointless isochronous frame\n"); • continue; • } • } else if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR) {
start_of_frame: • (*f)->state = F_GRABBING; • (*f)->buf.bytesused = 0; • len -= (sof - pos); • pos = sof; • if (cam->sensor.pix_format.pixelformat == • V4L2_PIX_FMT_JPEG) • sn9c120_write_jpegheader(cam, (*f)); • printk( "SOF detected: new video frame\n"); • if (len) • goto redo; • } else if ((*f)->state == F_GRABBING) { • eof = sn9c120_find_eof_header(cam, pos, len); • if (eof && eof < sof) • goto end_of_frame; /* (1) */
else { • if (cam->sensor.pix_format.pixelformat == • V4L2_PIX_FMT_SN9C10X || • cam->sensor.pix_format.pixelformat == • V4L2_PIX_FMT_JPEG) { • if (sof - pos >= soflen) { • eof = sof - soflen; • } else { /* remove header */ • eof = pos; • (*f)->buf.bytesused -= • (soflen - (sof - pos)); • } • goto end_of_frame; • } else { • printk( "SOF before expected EOF after " • "%lu bytes of image data\n", • (unsigned long) • ((*f)->buf.bytesused)); • goto start_of_frame; • } • } • } • }
resubmit_urb: • urb->dev = cam->usbdev; • err = usb_submit_urb(urb, GFP_ATOMIC); • if (err < 0 && err != -EPERM) { • cam->state |= DEV_MISCONFIGURED; • printk( "usb_submit_urb() failed\n"); • } • wake_up_interruptible(&cam->wait_frame); • }