📄 vivi.c
字号:
/* Updates stream time */ dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); dev->jiffies = jiffies; if (dev->ms >= 1000) { dev->ms -= 1000; dev->s++; if (dev->s >= 60) { dev->s -= 60; dev->m++; if (dev->m > 60) { dev->m -= 60; dev->h++; if (dev->h > 24) dev->h -= 24; } } } sprintf(dev->timestr, "%02d:%02d:%02d:%03d", dev->h, dev->m, dev->s, dev->ms); dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", dev->timestr, (unsigned long)tmpbuf, pos); /* Advice that buffer was filled */ buf->vb.field_count++; do_gettimeofday(&ts); buf->vb.ts = ts; buf->vb.state = VIDEOBUF_DONE;}static void vivi_thread_tick(struct vivi_fh *fh){ struct vivi_buffer *buf; struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *dma_q = &dev->vidq; unsigned long flags = 0; dprintk(dev, 1, "Thread tick\n"); spin_lock_irqsave(&dev->slock, flags); if (list_empty(&dma_q->active)) { dprintk(dev, 1, "No active queue to serve\n"); goto unlock; } buf = list_entry(dma_q->active.next, struct vivi_buffer, vb.queue); /* Nobody is waiting on this buffer, return */ if (!waitqueue_active(&buf->vb.done)) goto unlock; list_del(&buf->vb.queue); do_gettimeofday(&buf->vb.ts); /* Fill buffer */ vivi_fillbuff(fh, buf); dprintk(dev, 1, "filled buffer %p\n", buf); wake_up(&buf->vb.done); dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);unlock: spin_unlock_irqrestore(&dev->slock, flags); return;}#define frames_to_ms(frames) \ ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)static void vivi_sleep(struct vivi_fh *fh){ struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *dma_q = &dev->vidq; int timeout; DECLARE_WAITQUEUE(wait, current); dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__, (unsigned long)dma_q); add_wait_queue(&dma_q->wq, &wait); if (kthread_should_stop()) goto stop_task; /* Calculate time to wake up */ timeout = msecs_to_jiffies(frames_to_ms(1)); vivi_thread_tick(fh); schedule_timeout_interruptible(timeout);stop_task: remove_wait_queue(&dma_q->wq, &wait); try_to_freeze();}static int vivi_thread(void *data){ struct vivi_fh *fh = data; struct vivi_dev *dev = fh->dev; dprintk(dev, 1, "thread started\n"); set_freezable(); for (;;) { vivi_sleep(fh); if (kthread_should_stop()) break; } dprintk(dev, 1, "thread: exit\n"); return 0;}static int vivi_start_thread(struct vivi_fh *fh){ struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *dma_q = &dev->vidq; dma_q->frame = 0; dma_q->ini_jiffies = jiffies; dprintk(dev, 1, "%s\n", __func__); dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); if (IS_ERR(dma_q->kthread)) { printk(KERN_ERR "vivi: kernel_thread() failed\n"); return PTR_ERR(dma_q->kthread); } /* Wakes thread */ wake_up_interruptible(&dma_q->wq); dprintk(dev, 1, "returning from %s\n", __func__); return 0;}static void vivi_stop_thread(struct vivi_dmaqueue *dma_q){ struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); dprintk(dev, 1, "%s\n", __func__); /* shutdown control thread */ if (dma_q->kthread) { kthread_stop(dma_q->kthread); dma_q->kthread = NULL; }}/* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*/static intbuffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size){ struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = fh->dev; *size = fh->width*fh->height*2; if (0 == *count) *count = 32; while (*size * *count > vid_limit * 1024 * 1024) (*count)--; dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, *count, *size); return 0;}static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf){ struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = fh->dev; dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); if (in_interrupt()) BUG(); videobuf_vmalloc_free(&buf->vb); dprintk(dev, 1, "free_buffer: freed\n"); buf->vb.state = VIDEOBUF_NEEDS_INIT;}#define norm_maxw() 1024#define norm_maxh() 768static intbuffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field){ struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = fh->dev; struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); int rc; dprintk(dev, 1, "%s, field=%d\n", __func__, field); BUG_ON(NULL == fh->fmt); if (fh->width < 48 || fh->width > norm_maxw() || fh->height < 32 || fh->height > norm_maxh()) return -EINVAL; buf->vb.size = fh->width*fh->height*2; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; /* These properties only change when queue is idle, see s_fmt */ buf->fmt = fh->fmt; buf->vb.width = fh->width; buf->vb.height = fh->height; buf->vb.field = field; if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { rc = videobuf_iolock(vq, &buf->vb, NULL); if (rc < 0) goto fail; } buf->vb.state = VIDEOBUF_PREPARED; return 0;fail: free_buffer(vq, buf); return rc;}static voidbuffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){ struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = fh->dev; struct vivi_dmaqueue *vidq = &dev->vidq; dprintk(dev, 1, "%s\n", __func__); buf->vb.state = VIDEOBUF_QUEUED; list_add_tail(&buf->vb.queue, &vidq->active);}static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb){ struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = (struct vivi_dev *)fh->dev; dprintk(dev, 1, "%s\n", __func__); free_buffer(vq, buf);}static struct videobuf_queue_ops vivi_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};/* ------------------------------------------------------------------ IOCTL vidioc handling ------------------------------------------------------------------*/static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap){ strcpy(cap->driver, "vivi"); strcpy(cap->card, "vivi"); cap->version = VIVI_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; return 0;}static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f){ struct vivi_fmt *fmt; if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; fmt = &formats[f->index]; strlcpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0;}static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct vivi_fh *fh = priv; f->fmt.pix.width = fh->width; f->fmt.pix.height = fh->height; f->fmt.pix.field = fh->vb_vidq.field; f->fmt.pix.pixelformat = fh->fmt->fourcc; f->fmt.pix.bytesperline = (f->fmt.pix.width * fh->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; return (0);}static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct vivi_fh *fh = priv; struct vivi_dev *dev = fh->dev; struct vivi_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; fmt = get_format(f); if (!fmt) { dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n", f->fmt.pix.pixelformat); return -EINVAL; } field = f->fmt.pix.field; if (field == V4L2_FIELD_ANY) { field = V4L2_FIELD_INTERLACED; } else if (V4L2_FIELD_INTERLACED != field) { dprintk(dev, 1, "Field type invalid.\n"); return -EINVAL; } maxw = norm_maxw(); maxh = norm_maxh(); f->fmt.pix.field = field; if (f->fmt.pix.height < 32) f->fmt.pix.height = 32; if (f->fmt.pix.height > maxh) f->fmt.pix.height = maxh; if (f->fmt.pix.width < 48) f->fmt.pix.width = 48; if (f->fmt.pix.width > maxw) f->fmt.pix.width = maxw; f->fmt.pix.width &= ~0x03; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; return 0;}/*FIXME: This seems to be generic enough to be at videodev2 */static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f){ struct vivi_fh *fh = priv; struct videobuf_queue *q = &fh->vb_vidq; unsigned char r, g, b; int k, is_yuv; int ret = vidioc_try_fmt_vid_cap(file, fh, f); if (ret < 0) return (ret); mutex_lock(&q->vb_lock); if (videobuf_queue_is_busy(&fh->vb_vidq)) { dprintk(fh->dev, 1, "%s queue busy\n", __func__); ret = -EBUSY; goto out; } fh->fmt = get_format(f); fh->width = f->fmt.pix.width; fh->height = f->fmt.pix.height; fh->vb_vidq.field = f->fmt.pix.field; fh->type = f->type; /* precalculate color bar values to speed up rendering */ for (k = 0; k < 8; k++) { r = bars[k][0]; g = bars[k][1]; b = bars[k][2]; is_yuv = 0; switch (fh->fmt->fourcc) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: is_yuv = 1; break; case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: r >>= 3; g >>= 2; b >>= 3; break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_RGB555X: r >>= 3; g >>= 3; b >>= 3; break; } if (is_yuv) { fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ fh->bars[k][1] = TO_U(r, g, b); /* Cb */ fh->bars[k][2] = TO_V(r, g, b); /* Cr */ } else { fh->bars[k][0] = r; fh->bars[k][1] = g; fh->bars[k][2] = b; } } ret = 0;out: mutex_unlock(&q->vb_lock); return (ret);}static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p){ struct vivi_fh *fh = priv; return (videobuf_reqbufs(&fh->vb_vidq, p));}static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p){ struct vivi_fh *fh = priv; return (videobuf_querybuf(&fh->vb_vidq, p));}static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p){ struct vivi_fh *fh = priv; return (videobuf_qbuf(&fh->vb_vidq, p));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -