/* * video-buf generic routine to get the next available buffer */ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q, struct cx231xx_buffer **buf) { struct cx231xx_video_mode *vmode = container_of(dma_q, struct cx231xx_video_mode, vidq); struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode); char *outp; if (list_empty(&dma_q->active)) { cx231xx_err(DRIVER_NAME ": No active queue to serve\n"); dev->vbi_mode.bulk_ctl.buf = NULL; *buf = NULL; return; } /* Get the next buffer */ *buf = list_entry(dma_q->active.next, struct cx231xx_buffer, vb.queue); /* Cleans up buffer - Useful for testing for frame/URB loss */ outp = videobuf_to_vmalloc(&(*buf)->vb); memset(outp, 0, (*buf)->vb.size); dev->vbi_mode.bulk_ctl.buf = *buf; return; }
static void myvivi_timer_function(unsigned long data) { struct videobuf_vmalloc_memory *vbuf; /*1,构造数据 数据放在哪里,从队列的头部把第一个buffer取出来将数据填充进去。然后将&buf->done中将进程唤醒。 */ struct vb2_buffer *vb; //从本地队列取出第一个buffer。 if (list_empty(&myvivi_vb_local_queue->active)) {//若链表是空的表明还没有APP关心这里的数据 goto out; } //若不是空的则从队列的头部取出第一个videobuf。 vb = list_entry(myvivi_vb_local_queue.next, struct vb2_buffer, queue); if(!waitqueue_active(&vb->done_entry)) goto out; //填充数据: vbuf = videobuf_to_vmalloc(&vb); memset(vbuf, 0, vb->vb2_queue.bufs); /*2,唤醒进程:&buf->done中将进程唤醒。*/ wake_up(&vb->done_entry); out: /*3,修改timer的超时时间: 30fps--表示1秒内为30帧数据。 每30之1秒产生一帧数据。 */ mod_timer(&myvivi_timer, jiffies + HZ/30);//每隔时间产生一幅数据。HZ是1秒钟。 }
int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q, u8 *p_buffer, u32 bytes_to_copy) { u8 *p_out_buffer = NULL; u32 current_line_bytes_copied = 0; struct cx231xx_buffer *buf; u32 _line_size = dev->width << 1; void *startwrite; int offset, lencopy; buf = dev->vbi_mode.isoc_ctl.buf; if (buf == NULL) return -EINVAL; p_out_buffer = videobuf_to_vmalloc(&buf->vb); if (dma_q->bytes_left_in_line != _line_size) { current_line_bytes_copied = _line_size - dma_q->bytes_left_in_line; } offset = (dma_q->lines_completed * _line_size) + current_line_bytes_copied; /* prepare destination address */ startwrite = p_out_buffer + offset; lencopy = dma_q->bytes_left_in_line > bytes_to_copy ? bytes_to_copy : dma_q->bytes_left_in_line; memcpy(startwrite, p_buffer, lencopy); return 0; }
/*====================================================================*/ static void init_copy(struct video_data *video, bool index) { struct front_face *front = video->front; video->field_count = index; video->lines_copied = 0; video->prev_left = 0 ; video->dst = (char *)videobuf_to_vmalloc(front->curr_frame) + index * video->lines_size; video->vbi->copied = 0; /* set it here */ }
static void myvivi_timer_function(unsigned long data) { struct videobuf_buffer *vb; void *vbuf; struct timeval ts; /*1. 构造数据 * 从队列头部取出第一个video_buf,填充数据 */ /*1.1 从本地队列取出第一个videobuf*/ if (list_empty(&myvivi_vb_local_queue)) { goto out; } vb = list_entry(myvivi_vb_local_queue.next, struct videobuf_buffer, queue); /* Nobody is waiting on this buffer, return */ if (!waitqueue_active(&vb->done)) goto out; /*1.2 填充数据*/ vbuf = videobuf_to_vmalloc(vb); //memset(vbuf, 0xff, vb->size); myvivi_fillbuff(vb); vb->field_count++; do_gettimeofday(&ts); vb->ts = ts; vb->state = VIDEOBUF_DONE; /*1.3 把videobuf从本地队列中删除*/ list_del(&vb->queue); /*2. 唤醒进程*/ wake_up(&vb->done); out: /*3. 修改超时时间 30fps * 每 1/30 s ,产生一帧数据 */ mod_timer(&myvivi_timer, jiffies + HZ/30); }