* [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
@ 2009-07-15 23:54 Lamarque Vieira Souza
2009-07-16 12:59 ` Antoine Jacquet
` (2 more replies)
0 siblings, 3 replies; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-15 23:54 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
converting the driver to use videobuf. This version is synced with v4l-dvb as
of 15/Jul/2009.
Tested with Creative PC-CAM 880.
It basically:
. implements V4L2_CAP_STREAMING using videobuf;
. re-implements V4L2_CAP_READWRITE using videobuf;
. copies cam->udev->product to the card field of the v4l2_capability struct.
That gives more information to the users about the webcam;
. moves the brightness setting code from before requesting a frame (in
read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
executed only when the application requests a change in brightness and
not before every frame read;
. comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
libv4l do not work.
This patch fixes zr364xx for applications such as mplayer,
Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
with zr364xx chip.
Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
---
diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
--- a/linux/drivers/media/video/zr364xx.c Sun Jul 05 19:08:55 2009 -0300
+++ b/linux/drivers/media/video/zr364xx.c Wed Jul 15 20:50:34 2009 -0300
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -35,25 +37,34 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
#include "compat.h"
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
+#define FRAMES 1
#define MAX_FRAME_SIZE 100000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
@@ -102,24 +113,93 @@
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
+ ZR364XX_READ_FRAME */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 state;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt *fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -273,139 +353,120 @@
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
+
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
*buf)
+{
+ DBG("%s\n", __func__);
+
+ /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
+ * after running Skype on an AMD64 system. */
+ /*videobuf_waiton(&buf->vb, 0, 0);*/
+
+ if (in_interrupt())
+ BUG();
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer
*vb,
+ enum v4l2_field field)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+ cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
+ }
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ 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 void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer
*vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ DBG("%s\n", __func__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+
+ DBG("%s\n", __func__);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
/********************/
/* V4L2 integration */
/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
-
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
-
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
-
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
-
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
-
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
- }
-
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
-
- return size;
-}
-
-
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t
count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
- DBG("zr364xx_read: read %d bytes.", (int) count);
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -413,21 +474,275 @@
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+ (int) *ppos);
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+ /* NoMan Sux ! */
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
- return count;
+ return 0;
}
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+ struct zr364xx_buffer *buf,
+ int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ /*DBG("buffer to user\n");*/
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16 *)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ if (frm->lpvbits == NULL) {
+ DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
+ frm, cam, idx);
+ return -ENOMEM;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
+
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ } else if (cam->b_acquire) {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
+
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
+}
+
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
+}
+
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ sizeof(cap->bus_info));
+ cap->version = ZR364_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
return 0;
}
@@ -459,12 +774,11 @@
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -473,7 +787,7 @@
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -485,36 +799,42 @@
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -528,26 +848,59 @@
if (f->index > 0)
return -EINVAL;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
+
+ if (cam == NULL)
+ return -ENODEV;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
+ return -EINVAL;
+ }
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = cam->width;
+ f->fmt.pix.height = cam->height;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return 0;
+}
+
+static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -558,17 +911,26 @@
return 0;
}
-static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+/* Lamarque TODO: implement changing resolution on the fly */
+static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ if (ret < 0)
+ return ret;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -576,44 +938,264 @@
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int status;
+ int pipe;
+
+ pipe_info = purb->context;
+ /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ status = purb->status;
+ /* if shutting down, do not resubmit, exit immediately */
+ if (status == -ESHUTDOWN) {
+ DBG("%s, err shutdown\n", __func__);
+ pipe_info->err_count++;
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 ||
+ purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ if (status == 0)
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+ else {
+ pipe_info->err_count++;
+ DBG("%s: failed URB %d\n", __func__, status);
+ }
+
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
+ dev_err(&cam->udev->dev, "error submitting urb\n");
+ } else {
+ DBG("read pipe complete state 0\n");
+ }
+ return;
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->err_count = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
return 0;
}
-static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_pipeinfo *pipe_info;
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0)
+ pipe_info->state = 0;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
- DBG("ok!");
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ DBG("stop read pipe\n");
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ cam->b_acquire = 1;
+ } else {
+ res_free(cam);
+ }
+ DBG("%s: %d\n", __func__, res);
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -622,28 +1204,19 @@
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -659,6 +1232,14 @@
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -667,28 +1248,72 @@
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+
+ DBG("%s\n", __func__);
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+ cam = NULL;
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -711,40 +1336,43 @@
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- DBG("zr364xx_mmap: %ld\n", size);
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
+ return -ENODEV;
+ }
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return 0;
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -753,6 +1381,7 @@
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -769,6 +1398,10 @@
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -784,15 +1417,76 @@
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+ "Using less frames\n");
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ cam->pipe->transfer_buffer = NULL;
+ return -ENOMEM;
+ } else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -811,22 +1505,17 @@
if (cam->vdev == NULL) {
dev_err(&udev->dev, "cam->vdev: out of memory !\n");
kfree(cam);
+ cam = NULL;
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -853,21 +1542,53 @@
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
+ cam = NULL;
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ err = zr364xx_board_init(cam);
+ if (err) {
+ spin_lock_init(&cam->slock);
+ return err;
+ }
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -877,17 +1598,10 @@
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
- if (cam->vdev)
- video_unregister_device(cam->vdev);
- cam->vdev = NULL;
- kfree(cam->buffer);
- cam->buffer = NULL;
- vfree(cam->framebuf);
- cam->framebuf = NULL;
- kfree(cam);
- cam = NULL;
+ zr364xx_destroy(cam);
}
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-15 23:54 [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Lamarque Vieira Souza
@ 2009-07-16 12:59 ` Antoine Jacquet
2009-07-16 13:58 ` Lamarque Vieira Souza
2009-07-16 15:45 ` Mauro Carvalho Chehab
2009-07-20 23:46 ` [PATCH] Implement changing resolution on the fly " Lamarque Vieira Souza
2 siblings, 1 reply; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-16 12:59 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Thanks,
I successfully applied your patch and tested it with mplayer.
However I have the following trace each time I capture a frame:
[ 523.477064] BUG: scheduling while atomic: swapper/0/0x10010000
[ 523.477390] Modules linked in: zr364xx videodev v4l1_compat
v4l2_compat_ioctl32 videobuf_vmalloc videobuf_core binfmt_misc ipv6 fuse
ntfs it87 hwmon_vid snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss
snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi_event
snd_seq snd_timer snd_seq_device pcspkr snd snd_page_alloc
[ 523.477390] CPU 0:
[ 523.477390] Modules linked in: zr364xx videodev v4l1_compat
v4l2_compat_ioctl32 videobuf_vmalloc videobuf_core binfmt_misc ipv6 fuse
ntfs it87 hwmon_vid snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss
snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi_event
snd_seq snd_timer snd_seq_device pcspkr snd snd_page_alloc
[ 523.477390] Pid: 0, comm: swapper Not tainted 2.6.30.1 #1 Aspire T160
[ 523.477390] RIP: 0010:[<ffffffff8020fbcf>] [<ffffffff8020fbcf>]
default_idle+0x54/0x90
[ 523.477390] RSP: 0018:ffffffff807e3f38 EFLAGS: 00000246
[ 523.477390] RAX: ffffffff807e3fd8 RBX: 0000000000000000 RCX:
0000000000000000
[ 523.477390] RDX: 0000000000000000 RSI: 0000000000000001 RDI:
ffffffff8078d010
[ 523.477390] RBP: ffffffff8020b60e R08: 0000000000000000 R09:
0000000000000000
[ 523.477390] R10: 00000000000f423d R11: 0000000000000000 R12:
ffff88003f87d180
[ 523.477390] R13: 0000000000000000 R14: ffff88003e1e9940 R15:
ffff88003f87d180
[ 523.477390] FS: 00007f40f871e730(0000) GS:ffffffff80789000(0000)
knlGS:0000000000000000
[ 523.477390] CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
[ 523.477390] CR2: 00007f099e8c2008 CR3: 000000003c16c000 CR4:
00000000000006e0
[ 523.477390] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
0000000000000000
[ 523.477390] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
0000000000000400
[ 523.477390] Call Trace:
[ 523.477390] [<ffffffff805a1615>] ? notifier_call_chain+0x29/0x4c
[ 523.477390] [<ffffffff8020a124>] ? cpu_idle+0x23/0x5b
[ 523.477390] [<ffffffff807eba7c>] ? start_kernel+0x2e8/0x2f4
[ 523.477390] [<ffffffff807eb37e>] ? x86_64_start_kernel+0xe5/0xeb
I can trigger it each time I read a frame, for example using dd on
/dev/video0.
Did you have the same behavior?
Regards,
Antoine
Lamarque Vieira Souza wrote:
> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> converting the driver to use videobuf. This version is synced with v4l-dvb as
> of 15/Jul/2009.
>
> Tested with Creative PC-CAM 880.
>
> It basically:
> . implements V4L2_CAP_STREAMING using videobuf;
>
> . re-implements V4L2_CAP_READWRITE using videobuf;
>
> . copies cam->udev->product to the card field of the v4l2_capability struct.
> That gives more information to the users about the webcam;
>
> . moves the brightness setting code from before requesting a frame (in
> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> executed only when the application requests a change in brightness and
> not before every frame read;
>
> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> libv4l do not work.
>
> This patch fixes zr364xx for applications such as mplayer,
> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> with zr364xx chip.
>
> Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> ---
>
> diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
> --- a/linux/drivers/media/video/zr364xx.c Sun Jul 05 19:08:55 2009 -0300
> +++ b/linux/drivers/media/video/zr364xx.c Wed Jul 15 20:50:34 2009 -0300
> @@ -1,5 +1,5 @@
> /*
> - * Zoran 364xx based USB webcam module version 0.72
> + * Zoran 364xx based USB webcam module version 0.73
> *
> * Allows you to use your USB webcam with V4L2 applications
> * This is still in heavy developpement !
> @@ -10,6 +10,8 @@
> * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
> * V4L2 version inspired by meye.c driver
> *
> + * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
> + *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> * the Free Software Foundation; either version 2 of the License, or
> @@ -35,25 +37,34 @@
> #include <linux/highmem.h>
> #include <media/v4l2-common.h>
> #include <media/v4l2-ioctl.h>
> +#include <media/videobuf-vmalloc.h>
> #include "compat.h"
>
>
> /* Version Information */
> -#define DRIVER_VERSION "v0.72"
> +#define DRIVER_VERSION "v0.73"
> +#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
> #define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
> #define DRIVER_DESC "Zoran 364xx"
>
>
> /* Camera */
> -#define FRAMES 2
> +#define FRAMES 1
> #define MAX_FRAME_SIZE 100000
> #define BUFFER_SIZE 0x1000
> #define CTRL_TIMEOUT 500
>
> +#define ZR364XX_DEF_BUFS 4
> +#define ZR364XX_READ_IDLE 0
> +#define ZR364XX_READ_FRAME 1
>
> /* Debug macro */
> -#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
> -
> +#define DBG(fmt, args...) \
> + do { \
> + if (debug) { \
> + printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
> + } \
> + } while (0)
>
> /* Init methods, need to find nicer names for these
> * the exact names of the chipsets would be the best if someone finds it */
> @@ -102,24 +113,93 @@
>
> MODULE_DEVICE_TABLE(usb, device_table);
>
> +struct zr364xx_mode {
> + u32 color; /* output video color format */
> + u32 brightness; /* brightness */
> +};
> +
> +/* frame structure */
> +struct zr364xx_framei {
> + unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
> + ZR364XX_READ_FRAME */
> + void *lpvbits; /* image data */
> + unsigned long cur_size; /* current data copied to it */
> +};
> +
> +/* image buffer structure */
> +struct zr364xx_bufferi {
> + unsigned long dwFrames; /* number of frames in buffer */
> + struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
> +};
> +
> +struct zr364xx_dmaqueue {
> + struct list_head active;
> + struct zr364xx_camera *cam;
> +};
> +
> +struct zr364xx_pipeinfo {
> + u32 transfer_size;
> + u8 *transfer_buffer;
> + u32 state;
> + void *stream_urb;
> + void *cam; /* back pointer to zr364xx_camera struct */
> + u32 err_count;
> + u32 idx;
> +};
> +
> +struct zr364xx_fmt {
> + char *name;
> + u32 fourcc;
> + int depth;
> +};
> +
> +/* image formats. */
> +static const struct zr364xx_fmt formats[] = {
> + {
> + .name = "JPG",
> + .fourcc = V4L2_PIX_FMT_JPEG,
> + .depth = 24
> + }
> +};
>
> /* Camera stuff */
> struct zr364xx_camera {
> struct usb_device *udev; /* save off the usb device pointer */
> struct usb_interface *interface;/* the interface for this device */
> struct video_device *vdev; /* v4l video device */
> - u8 *framebuf;
> int nb;
> - unsigned char *buffer;
> + struct zr364xx_bufferi buffer;
> int skip;
> - int brightness;
> int width;
> int height;
> int method;
> struct mutex lock;
> + struct mutex open_lock;
> int users;
> +
> + spinlock_t slock;
> + struct zr364xx_dmaqueue vidq;
> + int resources;
> + int last_frame;
> + int cur_frame;
> + unsigned long frame_count;
> + int b_acquire;
> + struct zr364xx_pipeinfo pipe[1];
> +
> + u8 read_endpoint;
> +
> + const struct zr364xx_fmt *fmt;
> + struct videobuf_queue vb_vidq;
> + enum v4l2_buf_type type;
> + struct zr364xx_mode mode;
> };
>
> +/* buffer for one video frame */
> +struct zr364xx_buffer {
> + /* common v4l buffer stuff -- must be first */
> + struct videobuf_buffer vb;
> + const struct zr364xx_fmt *fmt;
> +};
>
> /* function used to send initialisation commands to the camera */
> static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
> @@ -273,139 +353,120 @@
> };
> static unsigned char header3;
>
> +/* ------------------------------------------------------------------
> + Videobuf operations
> + ------------------------------------------------------------------*/
>
> +static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
> + unsigned int *size)
> +{
> + struct zr364xx_camera *cam = vq->priv_data;
> +
> + *size = cam->width * cam->height * (cam->fmt->depth >> 3);
> +
> + if (*count == 0)
> + *count = ZR364XX_DEF_BUFS;
> +
> + while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
> + (*count)--;
> +
> + return 0;
> +}
> +
> +static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
> *buf)
> +{
> + DBG("%s\n", __func__);
> +
> + /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
> + * after running Skype on an AMD64 system. */
> + /*videobuf_waiton(&buf->vb, 0, 0);*/
> +
> + if (in_interrupt())
> + BUG();
> +
> + videobuf_vmalloc_free(&buf->vb);
> + buf->vb.state = VIDEOBUF_NEEDS_INIT;
> +}
> +
> +static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer
> *vb,
> + enum v4l2_field field)
> +{
> + struct zr364xx_camera *cam = vq->priv_data;
> + struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
> + vb);
> + int rc;
> +
> + DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
> + cam->fmt->name : "");
> + if (cam->fmt == NULL)
> + return -EINVAL;
> +
> + buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
> +
> + if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
> + DBG("invalid buffer prepare\n");
> + return -EINVAL;
> + }
> +
> + buf->fmt = cam->fmt;
> + buf->vb.width = cam->width;
> + buf->vb.height = cam->height;
> + buf->vb.field = field;
> +
> + if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
> + 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 void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer
> *vb)
> +{
> + struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
> + vb);
> + struct zr364xx_camera *cam = vq->priv_data;
> +
> + DBG("%s\n", __func__);
> +
> + buf->vb.state = VIDEOBUF_QUEUED;
> + list_add_tail(&buf->vb.queue, &cam->vidq.active);
> +}
> +
> +static void buffer_release(struct videobuf_queue *vq,
> + struct videobuf_buffer *vb)
> +{
> + struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
> + vb);
> +
> + DBG("%s\n", __func__);
> + free_buffer(vq, buf);
> +}
> +
> +static struct videobuf_queue_ops zr364xx_video_qops = {
> + .buf_setup = buffer_setup,
> + .buf_prepare = buffer_prepare,
> + .buf_queue = buffer_queue,
> + .buf_release = buffer_release,
> +};
>
> /********************/
> /* V4L2 integration */
> /********************/
> +static int zr364xx_vidioc_streamon(struct file *file, void *priv,
> + enum v4l2_buf_type type);
>
> -/* this function reads a full JPEG picture synchronously
> - * TODO: do it asynchronously... */
> -static int read_frame(struct zr364xx_camera *cam, int framenum)
> -{
> - int i, n, temp, head, size, actual_length;
> - unsigned char *ptr = NULL, *jpeg;
> -
> - redo:
> - /* hardware brightness */
> - n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
> - temp = (0x60 << 8) + 127 - cam->brightness;
> - n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
> -
> - /* during the first loop we are going to insert JPEG header */
> - head = 0;
> - /* this is the place in memory where we are going to build
> - * the JPEG image */
> - jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
> - /* read data... */
> - do {
> - n = usb_bulk_msg(cam->udev,
> - usb_rcvbulkpipe(cam->udev, 0x81),
> - cam->buffer, BUFFER_SIZE, &actual_length,
> - CTRL_TIMEOUT);
> - DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
> - DBG("bulk : n=%d size=%d", n, actual_length);
> - if (n < 0) {
> - dev_err(&cam->udev->dev, "error reading bulk msg\n");
> - return 0;
> - }
> - if (actual_length < 0 || actual_length > BUFFER_SIZE) {
> - dev_err(&cam->udev->dev, "wrong number of bytes\n");
> - return 0;
> - }
> -
> - /* swap bytes if camera needs it */
> - if (cam->method == METHOD0) {
> - u16 *buf = (u16*)cam->buffer;
> - for (i = 0; i < BUFFER_SIZE/2; i++)
> - swab16s(buf + i);
> - }
> -
> - /* write the JPEG header */
> - if (!head) {
> - DBG("jpeg header");
> - ptr = jpeg;
> - memcpy(ptr, header1, sizeof(header1));
> - ptr += sizeof(header1);
> - header3 = 0;
> - memcpy(ptr, &header3, 1);
> - ptr++;
> - memcpy(ptr, cam->buffer, 64);
> - ptr += 64;
> - header3 = 1;
> - memcpy(ptr, &header3, 1);
> - ptr++;
> - memcpy(ptr, cam->buffer + 64, 64);
> - ptr += 64;
> - memcpy(ptr, header2, sizeof(header2));
> - ptr += sizeof(header2);
> - memcpy(ptr, cam->buffer + 128,
> - actual_length - 128);
> - ptr += actual_length - 128;
> - head = 1;
> - DBG("header : %d %d %d %d %d %d %d %d %d",
> - cam->buffer[0], cam->buffer[1], cam->buffer[2],
> - cam->buffer[3], cam->buffer[4], cam->buffer[5],
> - cam->buffer[6], cam->buffer[7], cam->buffer[8]);
> - } else {
> - memcpy(ptr, cam->buffer, actual_length);
> - ptr += actual_length;
> - }
> - }
> - /* ... until there is no more */
> - while (actual_length == BUFFER_SIZE);
> -
> - /* we skip the 2 first frames which are usually buggy */
> - if (cam->skip) {
> - cam->skip--;
> - goto redo;
> - }
> -
> - /* go back to find the JPEG EOI marker */
> - size = ptr - jpeg;
> - ptr -= 2;
> - while (ptr > jpeg) {
> - if (*ptr == 0xFF && *(ptr + 1) == 0xD9
> - && *(ptr + 2) == 0xFF)
> - break;
> - ptr--;
> - }
> - if (ptr == jpeg)
> - DBG("No EOI marker");
> -
> - /* Sometimes there is junk data in the middle of the picture,
> - * we want to skip this bogus frames */
> - while (ptr > jpeg) {
> - if (*ptr == 0xFF && *(ptr + 1) == 0xFF
> - && *(ptr + 2) == 0xFF)
> - break;
> - ptr--;
> - }
> - if (ptr != jpeg) {
> - DBG("Bogus frame ? %d", cam->nb);
> - goto redo;
> - }
> -
> - DBG("jpeg : %d %d %d %d %d %d %d %d",
> - jpeg[0], jpeg[1], jpeg[2], jpeg[3],
> - jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
> -
> - return size;
> -}
> -
> -
> -static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
> +static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t
> count,
> loff_t * ppos)
> {
> - unsigned long count = cnt;
> - struct video_device *vdev = video_devdata(file);
> - struct zr364xx_camera *cam;
> + struct zr364xx_camera *cam = video_drvdata(file);
>
> - DBG("zr364xx_read: read %d bytes.", (int) count);
> -
> - if (vdev == NULL)
> - return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + DBG("%s\n", __func__);
>
> if (!buf)
> return -EINVAL;
> @@ -413,21 +474,275 @@
> if (!count)
> return -EINVAL;
>
> - /* NoMan Sux ! */
> - count = read_frame(cam, 0);
> + if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
> + zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
> + DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
> + (int) *ppos);
>
> - if (copy_to_user(buf, cam->framebuf, count))
> - return -EFAULT;
> + /* NoMan Sux ! */
> + return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
> + file->f_flags & O_NONBLOCK);
> + }
>
> - return count;
> + return 0;
> }
>
> +/* video buffer vmalloc implementation based partly on VIVI driver which is
> + * Copyright (c) 2006 by
> + * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
> + * Ted Walther <ted--a.t--enumera.com>
> + * John Sokol <sokol--a.t--videotechnology.com>
> + * http://v4l.videotechnology.com/
> + *
> + */
> +static void zr364xx_fillbuff(struct zr364xx_camera *cam,
> + struct zr364xx_buffer *buf,
> + int jpgsize)
> +{
> + int pos = 0;
> + struct timeval ts;
> + const char *tmpbuf;
> + char *vbuf = videobuf_to_vmalloc(&buf->vb);
> + unsigned long last_frame;
> + struct zr364xx_framei *frm;
> +
> + if (!vbuf)
> + return;
> +
> + last_frame = cam->last_frame;
> + if (last_frame != -1) {
> + frm = &cam->buffer.frame[last_frame];
> + tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
> + switch (buf->fmt->fourcc) {
> + case V4L2_PIX_FMT_JPEG:
> + buf->vb.size = jpgsize;
> + memcpy(vbuf, tmpbuf, buf->vb.size);
> + break;
> + default:
> + printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
> + }
> + cam->last_frame = -1;
> + } else {
> + printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
> + return;
> + }
> + DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
> + (unsigned long)vbuf, pos);
> + /* tell v4l buffer was filled */
> +
> + buf->vb.field_count = cam->frame_count * 2;
> + do_gettimeofday(&ts);
> + buf->vb.ts = ts;
> + buf->vb.state = VIDEOBUF_DONE;
> +}
> +
> +static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
> +{
> + struct zr364xx_dmaqueue *dma_q = &cam->vidq;
> + struct zr364xx_buffer *buf;
> + unsigned long flags = 0;
> + int rc = 0;
> +
> + DBG("wakeup: %p\n", &dma_q);
> + spin_lock_irqsave(&cam->slock, flags);
> +
> + if (list_empty(&dma_q->active)) {
> + DBG("No active queue to serve\n");
> + rc = -1;
> + goto unlock;
> + }
> + buf = list_entry(dma_q->active.next,
> + struct zr364xx_buffer, vb.queue);
> +
> + if (!waitqueue_active(&buf->vb.done)) {
> + /* no one active */
> + rc = -1;
> + goto unlock;
> + }
> + list_del(&buf->vb.queue);
> + do_gettimeofday(&buf->vb.ts);
> + DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
> + zr364xx_fillbuff(cam, buf, jpgsize);
> + wake_up(&buf->vb.done);
> + DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
> +unlock:
> + spin_unlock_irqrestore(&cam->slock, flags);
> + return 0;
> +}
> +
> +/* this function moves the usb stream read pipe data
> + * into the system buffers.
> + * returns 0 on success, EAGAIN if more data to process (call this
> + * function again).
> + */
> +static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
> + struct zr364xx_pipeinfo *pipe_info,
> + struct urb *purb)
> +{
> + unsigned char *pdest;
> + unsigned char *psrc;
> + s32 idx = -1;
> + struct zr364xx_framei *frm;
> + int i = 0;
> + unsigned char *ptr = NULL;
> +
> + /*DBG("buffer to user\n");*/
> + idx = cam->cur_frame;
> + frm = &cam->buffer.frame[idx];
> +
> + /* swap bytes if camera needs it */
> + if (cam->method == METHOD0) {
> + u16 *buf = (u16 *)pipe_info->transfer_buffer;
> + for (i = 0; i < purb->actual_length/2; i++)
> + swab16s(buf + i);
> + }
> +
> + /* search done. now find out if should be acquiring */
> + if (!cam->b_acquire) {
> + /* we found a frame, but this channel is turned off */
> + frm->ulState = ZR364XX_READ_IDLE;
> + return -EINVAL;
> + }
> +
> + if (frm->lpvbits == NULL) {
> + DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
> + frm, cam, idx);
> + return -ENOMEM;
> + }
> +
> + psrc = (u8 *)pipe_info->transfer_buffer;
> + ptr = pdest = frm->lpvbits;
> +
> + if (frm->ulState == ZR364XX_READ_IDLE) {
> + frm->ulState = ZR364XX_READ_FRAME;
> + frm->cur_size = 0;
> +
> + DBG("jpeg header, ");
> + memcpy(ptr, header1, sizeof(header1));
> + ptr += sizeof(header1);
> + header3 = 0;
> + memcpy(ptr, &header3, 1);
> + ptr++;
> + memcpy(ptr, psrc, 64);
> + ptr += 64;
> + header3 = 1;
> + memcpy(ptr, &header3, 1);
> + ptr++;
> + memcpy(ptr, psrc + 64, 64);
> + ptr += 64;
> + memcpy(ptr, header2, sizeof(header2));
> + ptr += sizeof(header2);
> + memcpy(ptr, psrc + 128,
> + purb->actual_length - 128);
> + ptr += purb->actual_length - 128;
> + DBG("header : %d %d %d %d %d %d %d %d %d\n",
> + psrc[0], psrc[1], psrc[2],
> + psrc[3], psrc[4], psrc[5],
> + psrc[6], psrc[7], psrc[8]);
> + frm->cur_size = ptr - pdest;
> + } else {
> + pdest += frm->cur_size;
> + memcpy(pdest, psrc, purb->actual_length);
> + frm->cur_size += purb->actual_length;
> + }
> + /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
> + purb->actual_length);*/
> +
> + if (purb->actual_length < pipe_info->transfer_size) {
> + DBG("****************Buffer[%d]full*************\n", idx);
> + cam->last_frame = cam->cur_frame;
> + cam->cur_frame++;
> + /* end of system frame ring buffer, start at zero */
> + if (cam->cur_frame == cam->buffer.dwFrames)
> + cam->cur_frame = 0;
> +
> + /* frame ready */
> + /* go back to find the JPEG EOI marker */
> + ptr = pdest = frm->lpvbits;
> + ptr += frm->cur_size - 2;
> + while (ptr > pdest) {
> + if (*ptr == 0xFF && *(ptr + 1) == 0xD9
> + && *(ptr + 2) == 0xFF)
> + break;
> + ptr--;
> + }
> + if (ptr == pdest)
> + DBG("No EOI marker\n");
> +
> + /* Sometimes there is junk data in the middle of the picture,
> + * we want to skip this bogus frames */
> + while (ptr > pdest) {
> + if (*ptr == 0xFF && *(ptr + 1) == 0xFF
> + && *(ptr + 2) == 0xFF)
> + break;
> + ptr--;
> + }
> + if (ptr != pdest) {
> + DBG("Bogus frame ? %d\n", ++(cam->nb));
> + } else if (cam->b_acquire) {
> + /* we skip the 2 first frames which are usually buggy */
> + if (cam->skip)
> + cam->skip--;
> + else {
> + DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
> + frm->cur_size,
> + pdest[0], pdest[1], pdest[2], pdest[3],
> + pdest[4], pdest[5], pdest[6], pdest[7]);
> +
> + zr364xx_got_frame(cam, frm->cur_size);
> + }
> + }
> + cam->frame_count++;
> + frm->ulState = ZR364XX_READ_IDLE;
> + frm->cur_size = 0;
> + }
> + /* done successfully */
> + return 0;
> +}
> +
> +static int res_get(struct zr364xx_camera *cam)
> +{
> + /* is it free? */
> + mutex_lock(&cam->lock);
> + if (cam->resources) {
> + /* no, someone else uses it */
> + mutex_unlock(&cam->lock);
> + return 0;
> + }
> + /* it's free, grab it */
> + cam->resources = 1;
> + DBG("res: get\n");
> + mutex_unlock(&cam->lock);
> + return 1;
> +}
> +
> +static inline int res_check(struct zr364xx_camera *cam)
> +{
> + return cam->resources;
> +}
> +
> +static void res_free(struct zr364xx_camera *cam)
> +{
> + mutex_lock(&cam->lock);
> + cam->resources = 0;
> + mutex_unlock(&cam->lock);
> + DBG("res: put\n");
> +}
>
> static int zr364xx_vidioc_querycap(struct file *file, void *priv,
> struct v4l2_capability *cap)
> {
> - strcpy(cap->driver, DRIVER_DESC);
> - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
> + struct zr364xx_camera *cam = video_drvdata(file);
> +
> + strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
> + strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
> + strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
> + sizeof(cap->bus_info));
> + cap->version = ZR364_VERSION_CODE;
> + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
> + V4L2_CAP_READWRITE |
> + V4L2_CAP_STREAMING;
> +
> return 0;
> }
>
> @@ -459,12 +774,11 @@
> static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
> struct v4l2_queryctrl *c)
> {
> - struct video_device *vdev = video_devdata(file);
> struct zr364xx_camera *cam;
>
> - if (vdev == NULL)
> + if (file == NULL)
> return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + cam = video_drvdata(file);
>
> switch (c->id) {
> case V4L2_CID_BRIGHTNESS:
> @@ -473,7 +787,7 @@
> c->minimum = 0;
> c->maximum = 127;
> c->step = 1;
> - c->default_value = cam->brightness;
> + c->default_value = cam->mode.brightness;
> c->flags = 0;
> break;
> default:
> @@ -485,36 +799,42 @@
> static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
> struct v4l2_control *c)
> {
> - struct video_device *vdev = video_devdata(file);
> struct zr364xx_camera *cam;
> + int temp;
>
> - if (vdev == NULL)
> + if (file == NULL)
> return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + cam = video_drvdata(file);
>
> switch (c->id) {
> case V4L2_CID_BRIGHTNESS:
> - cam->brightness = c->value;
> + cam->mode.brightness = c->value;
> + /* hardware brightness */
> + mutex_lock(&cam->lock);
> + send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
> + temp = (0x60 << 8) + 127 - cam->mode.brightness;
> + send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
> + mutex_unlock(&cam->lock);
> break;
> default:
> return -EINVAL;
> }
> +
> return 0;
> }
>
> static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
> struct v4l2_control *c)
> {
> - struct video_device *vdev = video_devdata(file);
> struct zr364xx_camera *cam;
>
> - if (vdev == NULL)
> + if (file == NULL)
> return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + cam = video_drvdata(file);
>
> switch (c->id) {
> case V4L2_CID_BRIGHTNESS:
> - c->value = cam->brightness;
> + c->value = cam->mode.brightness;
> break;
> default:
> return -EINVAL;
> @@ -528,26 +848,59 @@
> if (f->index > 0)
> return -EINVAL;
> f->flags = V4L2_FMT_FLAG_COMPRESSED;
> - strcpy(f->description, "JPEG");
> - f->pixelformat = V4L2_PIX_FMT_JPEG;
> + strcpy(f->description, formats[0].name);
> + f->pixelformat = formats[0].fourcc;
> return 0;
> }
>
> +static char *decode_fourcc(__u32 pixelformat, char *buf)
> +{
> + buf[0] = pixelformat & 0xff;
> + buf[1] = (pixelformat >> 8) & 0xff;
> + buf[2] = (pixelformat >> 16) & 0xff;
> + buf[3] = (pixelformat >> 24) & 0xff;
> + buf[4] = '\0';
> + return buf;
> +}
> +
> static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
> struct v4l2_format *f)
> {
> - struct video_device *vdev = video_devdata(file);
> + struct zr364xx_camera *cam = video_drvdata(file);
> + char pixelformat_name[5];
> +
> + if (cam == NULL)
> + return -ENODEV;
> +
> + if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
> + DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
> + decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
> + return -EINVAL;
> + }
> +
> + f->fmt.pix.field = V4L2_FIELD_NONE;
> + f->fmt.pix.width = cam->width;
> + f->fmt.pix.height = cam->height;
> + f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
> + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
> + f->fmt.pix.colorspace = 0;
> + f->fmt.pix.priv = 0;
> + DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
> + decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
> + f->fmt.pix.field);
> + return 0;
> +}
> +
> +static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
> + struct v4l2_format *f)
> +{
> struct zr364xx_camera *cam;
>
> - if (vdev == NULL)
> + if (file == NULL)
> return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + cam = video_drvdata(file);
>
> - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
> - return -EINVAL;
> - if (f->fmt.pix.field != V4L2_FIELD_ANY &&
> - f->fmt.pix.field != V4L2_FIELD_NONE)
> - return -EINVAL;
> + f->fmt.pix.pixelformat = formats[0].fourcc;
> f->fmt.pix.field = V4L2_FIELD_NONE;
> f->fmt.pix.width = cam->width;
> f->fmt.pix.height = cam->height;
> @@ -558,17 +911,26 @@
> return 0;
> }
>
> -static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
> +/* Lamarque TODO: implement changing resolution on the fly */
> +static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
> struct v4l2_format *f)
> {
> - struct video_device *vdev = video_devdata(file);
> - struct zr364xx_camera *cam;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + struct videobuf_queue *q = &cam->vb_vidq;
> + char pixelformat_name[5];
> + int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
>
> - if (vdev == NULL)
> - return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + if (ret < 0)
> + return ret;
>
> - f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
> + mutex_lock(&q->vb_lock);
> +
> + if (videobuf_queue_is_busy(&cam->vb_vidq)) {
> + DBG("%s queue busy\n", __func__);
> + ret = -EBUSY;
> + goto out;
> + }
> +
> f->fmt.pix.field = V4L2_FIELD_NONE;
> f->fmt.pix.width = cam->width;
> f->fmt.pix.height = cam->height;
> @@ -576,44 +938,264 @@
> f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
> f->fmt.pix.colorspace = 0;
> f->fmt.pix.priv = 0;
> + cam->vb_vidq.field = f->fmt.pix.field;
> + cam->mode.color = V4L2_PIX_FMT_JPEG;
> + ret = 0;
> +
> +out:
> + mutex_unlock(&q->vb_lock);
> +
> + DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
> + decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
> + f->fmt.pix.field);
> + return ret;
> +}
> +
> +static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
> + struct v4l2_requestbuffers *p)
> +{
> + int rc;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + rc = videobuf_reqbufs(&cam->vb_vidq, p);
> + return rc;
> +}
> +
> +static int zr364xx_vidioc_querybuf(struct file *file,
> + void *priv,
> + struct v4l2_buffer *p)
> +{
> + int rc;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + rc = videobuf_querybuf(&cam->vb_vidq, p);
> + return rc;
> +}
> +
> +static int zr364xx_vidioc_qbuf(struct file *file,
> + void *priv,
> + struct v4l2_buffer *p)
> +{
> + int rc;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + DBG("%s\n", __func__);
> + rc = videobuf_qbuf(&cam->vb_vidq, p);
> + return rc;
> +}
> +
> +static int zr364xx_vidioc_dqbuf(struct file *file,
> + void *priv,
> + struct v4l2_buffer *p)
> +{
> + int rc;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + DBG("%s\n", __func__);
> + rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
> + return rc;
> +}
> +
> +static void read_pipe_completion(struct urb *purb)
> +{
> + struct zr364xx_pipeinfo *pipe_info;
> + struct zr364xx_camera *cam;
> + int status;
> + int pipe;
> +
> + pipe_info = purb->context;
> + /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
> + if (pipe_info == NULL) {
> + printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
> + return;
> + }
> +
> + cam = pipe_info->cam;
> + if (cam == NULL) {
> + printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
> + return;
> + }
> +
> + status = purb->status;
> + /* if shutting down, do not resubmit, exit immediately */
> + if (status == -ESHUTDOWN) {
> + DBG("%s, err shutdown\n", __func__);
> + pipe_info->err_count++;
> + return;
> + }
> +
> + if (pipe_info->state == 0) {
> + DBG("exiting USB pipe\n");
> + return;
> + }
> +
> + if (purb->actual_length < 0 ||
> + purb->actual_length > pipe_info->transfer_size) {
> + dev_err(&cam->udev->dev, "wrong number of bytes\n");
> + return;
> + }
> +
> + if (status == 0)
> + zr364xx_read_video_callback(cam, pipe_info, purb);
> + else {
> + pipe_info->err_count++;
> + DBG("%s: failed URB %d\n", __func__, status);
> + }
> +
> + pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
> +
> + /* reuse urb */
> + usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
> + pipe,
> + pipe_info->transfer_buffer,
> + pipe_info->transfer_size,
> + read_pipe_completion, pipe_info);
> +
> + if (pipe_info->state != 0) {
> + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
> + dev_err(&cam->udev->dev, "error submitting urb\n");
> + } else {
> + DBG("read pipe complete state 0\n");
> + }
> + return;
> +}
> +
> +static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
> +{
> + int pipe;
> + int retval;
> + struct zr364xx_pipeinfo *pipe_info = cam->pipe;
> + pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
> + DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
> +
> + pipe_info->state = 1;
> + pipe_info->err_count = 0;
> + pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
> + if (!pipe_info->stream_urb) {
> + dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
> + return -ENOMEM;
> + }
> + /* transfer buffer allocated in board_init */
> + usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
> + pipe,
> + pipe_info->transfer_buffer,
> + pipe_info->transfer_size,
> + read_pipe_completion, pipe_info);
> +
> + DBG("submitting URB %p\n", pipe_info->stream_urb);
> + retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
> + if (retval) {
> + printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
> + return retval;
> + }
> +
> return 0;
> }
>
> -static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
> - struct v4l2_format *f)
> +static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
> {
> - struct video_device *vdev = video_devdata(file);
> - struct zr364xx_camera *cam;
> + struct zr364xx_pipeinfo *pipe_info;
>
> - if (vdev == NULL)
> - return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + if (cam == NULL) {
> + printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
> + return;
> + }
> + DBG("stop read pipe\n");
> + pipe_info = cam->pipe;
> + if (pipe_info) {
> + if (pipe_info->state != 0)
> + pipe_info->state = 0;
>
> - if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
> - return -EINVAL;
> - if (f->fmt.pix.field != V4L2_FIELD_ANY &&
> - f->fmt.pix.field != V4L2_FIELD_NONE)
> - return -EINVAL;
> - f->fmt.pix.field = V4L2_FIELD_NONE;
> - f->fmt.pix.width = cam->width;
> - f->fmt.pix.height = cam->height;
> - f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
> - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
> - f->fmt.pix.colorspace = 0;
> - f->fmt.pix.priv = 0;
> - DBG("ok!");
> + if (pipe_info->stream_urb) {
> + /* cancel urb */
> + usb_kill_urb(pipe_info->stream_urb);
> + usb_free_urb(pipe_info->stream_urb);
> + pipe_info->stream_urb = NULL;
> + }
> + }
> + DBG("stop read pipe\n");
> + return;
> +}
> +
> +/* starts acquisition process */
> +static int zr364xx_start_acquire(struct zr364xx_camera *cam)
> +{
> + int j;
> +
> + DBG("start acquire\n");
> +
> + cam->last_frame = -1;
> + cam->cur_frame = 0;
> + for (j = 0; j < FRAMES; j++) {
> + cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
> + cam->buffer.frame[j].cur_size = 0;
> + }
> + return 0;
> +}
> +
> +static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
> +{
> + cam->b_acquire = 0;
> return 0;
> }
>
> static int zr364xx_vidioc_streamon(struct file *file, void *priv,
> enum v4l2_buf_type type)
> {
> - return 0;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + int j;
> + int res;
> +
> + DBG("%s\n", __func__);
> +
> + if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> + dev_err(&cam->udev->dev, "invalid fh type0\n");
> + return -EINVAL;
> + }
> + if (cam->type != type) {
> + dev_err(&cam->udev->dev, "invalid fh type1\n");
> + return -EINVAL;
> + }
> +
> + if (!res_get(cam)) {
> + dev_err(&cam->udev->dev, "stream busy\n");
> + return -EBUSY;
> + }
> +
> + cam->last_frame = -1;
> + cam->cur_frame = 0;
> + cam->frame_count = 0;
> + for (j = 0; j < FRAMES; j++) {
> + cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
> + cam->buffer.frame[j].cur_size = 0;
> + }
> + res = videobuf_streamon(&cam->vb_vidq);
> + if (res == 0) {
> + zr364xx_start_acquire(cam);
> + cam->b_acquire = 1;
> + } else {
> + res_free(cam);
> + }
> + DBG("%s: %d\n", __func__, res);
> + return res;
> }
>
> static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
> enum v4l2_buf_type type)
> {
> + int res;
> + struct zr364xx_camera *cam = video_drvdata(file);
> +
> + DBG("%s\n", __func__);
> + if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
> + dev_err(&cam->udev->dev, "invalid fh type0\n");
> + return -EINVAL;
> + }
> + if (cam->type != type) {
> + dev_err(&cam->udev->dev, "invalid fh type1\n");
> + return -EINVAL;
> + }
> + zr364xx_stop_acquire(cam);
> + res = videobuf_streamoff(&cam->vb_vidq);
> + if (res < 0)
> + return res;
> + res_free(cam);
> return 0;
> }
>
> @@ -622,28 +1204,19 @@
> static int zr364xx_open(struct file *file)
> {
> struct video_device *vdev = video_devdata(file);
> - struct zr364xx_camera *cam = video_get_drvdata(vdev);
> + struct zr364xx_camera *cam = video_drvdata(file);
> struct usb_device *udev = cam->udev;
> int i, err;
>
> - DBG("zr364xx_open");
> + DBG("%s\n", __func__);
>
> - mutex_lock(&cam->lock);
> + mutex_lock(&cam->open_lock);
>
> if (cam->users) {
> err = -EBUSY;
> goto out;
> }
>
> - if (!cam->framebuf) {
> - cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
> - if (!cam->framebuf) {
> - dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
> - err = -ENOMEM;
> - goto out;
> - }
> - }
> -
> for (i = 0; init[cam->method][i].size != -1; i++) {
> err =
> send_control_msg(udev, 1, init[cam->method][i].value,
> @@ -659,6 +1232,14 @@
> cam->skip = 2;
> cam->users++;
> file->private_data = vdev;
> + cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> + cam->fmt = formats;
> +
> + videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
> + NULL, &cam->slock,
> + cam->type,
> + V4L2_FIELD_NONE,
> + sizeof(struct zr364xx_buffer), cam);
>
> /* Added some delay here, since opening/closing the camera quickly,
> * like Ekiga does during its startup, can crash the webcam
> @@ -667,28 +1248,72 @@
> err = 0;
>
> out:
> - mutex_unlock(&cam->lock);
> + mutex_unlock(&cam->open_lock);
> + DBG("%s: %d\n", __func__, err);
> return err;
> }
>
> +static void zr364xx_destroy(struct zr364xx_camera *cam)
> +{
> + unsigned long i;
> +
> + if (!cam) {
> + printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
> + return;
> + }
> + mutex_lock(&cam->open_lock);
> + if (cam->vdev)
> + video_unregister_device(cam->vdev);
> + cam->vdev = NULL;
> +
> + /* stops the read pipe if it is running */
> + if (cam->b_acquire)
> + zr364xx_stop_acquire(cam);
> +
> + zr364xx_stop_readpipe(cam);
> +
> + /* release sys buffers */
> + for (i = 0; i < FRAMES; i++) {
> + if (cam->buffer.frame[i].lpvbits) {
> + DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
> + vfree(cam->buffer.frame[i].lpvbits);
> + }
> + cam->buffer.frame[i].lpvbits = NULL;
> + }
> +
> + /* release transfer buffer */
> + kfree(cam->pipe->transfer_buffer);
> + cam->pipe->transfer_buffer = NULL;
> +
> + DBG("%s\n", __func__);
> + mutex_unlock(&cam->open_lock);
> + kfree(cam);
> + cam = NULL;
> +}
>
> /* release the camera */
> static int zr364xx_release(struct file *file)
> {
> - struct video_device *vdev = video_devdata(file);
> struct zr364xx_camera *cam;
> struct usb_device *udev;
> int i, err;
>
> - DBG("zr364xx_release");
> + DBG("%s\n", __func__);
> + cam = video_drvdata(file);
>
> - if (vdev == NULL)
> + if (!cam)
> return -ENODEV;
> - cam = video_get_drvdata(vdev);
>
> + mutex_lock(&cam->open_lock);
> udev = cam->udev;
>
> - mutex_lock(&cam->lock);
> + /* turn off stream */
> + if (res_check(cam)) {
> + if (cam->b_acquire)
> + zr364xx_stop_acquire(cam);
> + videobuf_streamoff(&cam->vb_vidq);
> + res_free(cam);
> + }
>
> cam->users--;
> file->private_data = NULL;
> @@ -711,40 +1336,43 @@
> err = 0;
>
> out:
> - mutex_unlock(&cam->lock);
> + mutex_unlock(&cam->open_lock);
> +
> return err;
> }
>
>
> static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
> {
> - void *pos;
> - unsigned long start = vma->vm_start;
> - unsigned long size = vma->vm_end - vma->vm_start;
> - struct video_device *vdev = video_devdata(file);
> - struct zr364xx_camera *cam;
> + struct zr364xx_camera *cam = video_drvdata(file);
> + int ret;
>
> - DBG("zr364xx_mmap: %ld\n", size);
> + if (cam == NULL) {
> + DBG("%s: cam == NULL\n", __func__);
> + return -ENODEV;
> + }
> + DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
>
> - if (vdev == NULL)
> - return -ENODEV;
> - cam = video_get_drvdata(vdev);
> + ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
>
> - pos = cam->framebuf;
> - while (size > 0) {
> - if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
> - return -EAGAIN;
> - start += PAGE_SIZE;
> - pos += PAGE_SIZE;
> - if (size > PAGE_SIZE)
> - size -= PAGE_SIZE;
> - else
> - size = 0;
> - }
> -
> - return 0;
> + DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
> + (unsigned long)vma->vm_start,
> + (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
> + return ret;
> }
>
> +static unsigned int zr364xx_poll(struct file *file,
> + struct poll_table_struct *wait)
> +{
> + struct zr364xx_camera *cam = video_drvdata(file);
> + struct videobuf_queue *q = &cam->vb_vidq;
> + DBG("%s\n", __func__);
> +
> + if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
> + return POLLERR;
> +
> + return videobuf_poll_stream(file, q, wait);
> +}
>
> static const struct v4l2_file_operations zr364xx_fops = {
> .owner = THIS_MODULE,
> @@ -753,6 +1381,7 @@
> .read = zr364xx_read,
> .mmap = zr364xx_mmap,
> .ioctl = video_ioctl2,
> + .poll = zr364xx_poll,
> };
>
> static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
> @@ -769,6 +1398,10 @@
> .vidioc_queryctrl = zr364xx_vidioc_queryctrl,
> .vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
> .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
> + .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
> + .vidioc_querybuf = zr364xx_vidioc_querybuf,
> + .vidioc_qbuf = zr364xx_vidioc_qbuf,
> + .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
> };
>
> static struct video_device zr364xx_template = {
> @@ -784,15 +1417,76 @@
> /*******************/
> /* USB integration */
> /*******************/
> +static int zr364xx_board_init(struct zr364xx_camera *cam)
> +{
> + struct zr364xx_pipeinfo *pipe = cam->pipe;
> + unsigned long i;
> +
> + DBG("board init: %p\n", cam);
> + memset(pipe, 0, sizeof(*pipe));
> + pipe->cam = cam;
> + pipe->transfer_size = BUFFER_SIZE;
> +
> + pipe->transfer_buffer = kzalloc(pipe->transfer_size,
> + GFP_KERNEL);
> + if (pipe->transfer_buffer == NULL) {
> + DBG("out of memory!\n");
> + return -ENOMEM;
> + }
> +
> + cam->b_acquire = 0;
> + cam->frame_count = 0;
> +
> + /*** start create system buffers ***/
> + for (i = 0; i < FRAMES; i++) {
> + /* always allocate maximum size for system buffers */
> + cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
> +
> + DBG("valloc %p, idx %lu, pdata %p\n",
> + &cam->buffer.frame[i], i,
> + cam->buffer.frame[i].lpvbits);
> + if (cam->buffer.frame[i].lpvbits == NULL) {
> + printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
> + "Using less frames\n");
> + break;
> + }
> + }
> +
> + if (i == 0) {
> + printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
> + kfree(cam->pipe->transfer_buffer);
> + cam->pipe->transfer_buffer = NULL;
> + return -ENOMEM;
> + } else
> + cam->buffer.dwFrames = i;
> +
> + /* make sure internal states are set */
> + for (i = 0; i < FRAMES; i++) {
> + cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
> + cam->buffer.frame[i].cur_size = 0;
> + }
> +
> + cam->cur_frame = 0;
> + cam->last_frame = -1;
> + /*** end create system buffers ***/
> +
> + /* start read pipe */
> + zr364xx_start_readpipe(cam);
> + DBG(": board initialized\n");
> + return 0;
> +}
>
> static int zr364xx_probe(struct usb_interface *intf,
> const struct usb_device_id *id)
> {
> struct usb_device *udev = interface_to_usbdev(intf);
> struct zr364xx_camera *cam = NULL;
> + struct usb_host_interface *iface_desc;
> + struct usb_endpoint_descriptor *endpoint;
> int err;
> + int i;
>
> - DBG("probing...");
> + DBG("probing...\n");
>
> dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
> dev_info(&intf->dev, "model %04x:%04x detected\n",
> @@ -811,22 +1505,17 @@
> if (cam->vdev == NULL) {
> dev_err(&udev->dev, "cam->vdev: out of memory !\n");
> kfree(cam);
> + cam = NULL;
> return -ENOMEM;
> }
> memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
> + cam->vdev->parent = &intf->dev;
> video_set_drvdata(cam->vdev, cam);
> if (debug)
> cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
>
> cam->udev = udev;
>
> - if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
> - dev_info(&udev->dev, "cam->buffer: out of memory !\n");
> - video_device_release(cam->vdev);
> - kfree(cam);
> - return -ENODEV;
> - }
> -
> switch (mode) {
> case 1:
> dev_info(&udev->dev, "160x120 mode selected\n");
> @@ -853,21 +1542,53 @@
> header2[439] = cam->width / 256;
> header2[440] = cam->width % 256;
>
> + cam->users = 0;
> cam->nb = 0;
> - cam->brightness = 64;
> + cam->mode.brightness = 64;
> mutex_init(&cam->lock);
> + mutex_init(&cam->open_lock);
>
> + DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
> +
> + /* set up the endpoint information */
> + iface_desc = intf->cur_altsetting;
> + DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
> + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
> + endpoint = &iface_desc->endpoint[i].desc;
> + if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
> + /* we found the bulk in endpoint */
> + cam->read_endpoint = endpoint->bEndpointAddress;
> + }
> + }
> +
> + if (!cam->read_endpoint) {
> + dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
> + return -ENOMEM;
> + }
> +
> + /* v4l */
> + INIT_LIST_HEAD(&cam->vidq.active);
> + cam->vidq.cam = cam;
> err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
> if (err) {
> dev_err(&udev->dev, "video_register_device failed\n");
> video_device_release(cam->vdev);
> - kfree(cam->buffer);
> kfree(cam);
> + cam = NULL;
> return err;
> }
>
> usb_set_intfdata(intf, cam);
>
> + /* load zr364xx board specific */
> + err = zr364xx_board_init(cam);
> + if (err) {
> + spin_lock_init(&cam->slock);
> + return err;
> + }
> +
> + spin_lock_init(&cam->slock);
> +
> dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
> cam->vdev->num);
> return 0;
> @@ -877,17 +1598,10 @@
> static void zr364xx_disconnect(struct usb_interface *intf)
> {
> struct zr364xx_camera *cam = usb_get_intfdata(intf);
> + videobuf_mmap_free(&cam->vb_vidq);
> usb_set_intfdata(intf, NULL);
> dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
> - if (cam->vdev)
> - video_unregister_device(cam->vdev);
> - cam->vdev = NULL;
> - kfree(cam->buffer);
> - cam->buffer = NULL;
> - vfree(cam->framebuf);
> - cam->framebuf = NULL;
> - kfree(cam);
> - cam = NULL;
> + zr364xx_destroy(cam);
> }
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-16 12:59 ` Antoine Jacquet
@ 2009-07-16 13:58 ` Lamarque Vieira Souza
0 siblings, 0 replies; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-16 13:58 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Em Quinta-feira 16 Julho 2009, Antoine Jacquet escreveu:
> Thanks,
>
> I successfully applied your patch and tested it with mplayer.
> However I have the following trace each time I capture a frame:
No, I do not have this problem neither in 2.6.28 (vanilla), 2.6.29.3 (vanilla
source and v4l-dvb) and 2.6.30.1 (vanilla and v4l-dvb). My notebook is single
core, maybe this problem is related to SMP. I will try to test the patch on a
dual core processor.
> [ 523.477064] BUG: scheduling while atomic: swapper/0/0x10010000
> [ 523.477390] Modules linked in: zr364xx videodev v4l1_compat
> v4l2_compat_ioctl32 videobuf_vmalloc videobuf_core binfmt_misc ipv6 fuse
> ntfs it87 hwmon_vid snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss
> snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi_event
> snd_seq snd_timer snd_seq_device pcspkr snd snd_page_alloc
> [ 523.477390] CPU 0:
> [ 523.477390] Modules linked in: zr364xx videodev v4l1_compat
> v4l2_compat_ioctl32 videobuf_vmalloc videobuf_core binfmt_misc ipv6 fuse
> ntfs it87 hwmon_vid snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm_oss
> snd_mixer_oss snd_pcm snd_seq_dummy snd_seq_oss snd_seq_midi_event
> snd_seq snd_timer snd_seq_device pcspkr snd snd_page_alloc
> [ 523.477390] Pid: 0, comm: swapper Not tainted 2.6.30.1 #1 Aspire T160
> [ 523.477390] RIP: 0010:[<ffffffff8020fbcf>] [<ffffffff8020fbcf>]
> default_idle+0x54/0x90
> [ 523.477390] RSP: 0018:ffffffff807e3f38 EFLAGS: 00000246
> [ 523.477390] RAX: ffffffff807e3fd8 RBX: 0000000000000000 RCX:
> 0000000000000000
> [ 523.477390] RDX: 0000000000000000 RSI: 0000000000000001 RDI:
> ffffffff8078d010
> [ 523.477390] RBP: ffffffff8020b60e R08: 0000000000000000 R09:
> 0000000000000000
> [ 523.477390] R10: 00000000000f423d R11: 0000000000000000 R12:
> ffff88003f87d180
> [ 523.477390] R13: 0000000000000000 R14: ffff88003e1e9940 R15:
> ffff88003f87d180
> [ 523.477390] FS: 00007f40f871e730(0000) GS:ffffffff80789000(0000)
> knlGS:0000000000000000
> [ 523.477390] CS: 0010 DS: 0018 ES: 0018 CR0: 000000008005003b
> [ 523.477390] CR2: 00007f099e8c2008 CR3: 000000003c16c000 CR4:
> 00000000000006e0
> [ 523.477390] DR0: 0000000000000000 DR1: 0000000000000000 DR2:
> 0000000000000000
> [ 523.477390] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7:
> 0000000000000400
> [ 523.477390] Call Trace:
> [ 523.477390] [<ffffffff805a1615>] ? notifier_call_chain+0x29/0x4c
> [ 523.477390] [<ffffffff8020a124>] ? cpu_idle+0x23/0x5b
> [ 523.477390] [<ffffffff807eba7c>] ? start_kernel+0x2e8/0x2f4
> [ 523.477390] [<ffffffff807eb37e>] ? x86_64_start_kernel+0xe5/0xeb
>
> I can trigger it each time I read a frame, for example using dd on
> /dev/video0.
> Did you have the same behavior?
>
> Regards,
>
> Antoine
>
> Lamarque Vieira Souza wrote:
> > This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> > converting the driver to use videobuf. This version is synced with
> > v4l-dvb as of 15/Jul/2009.
> >
> > Tested with Creative PC-CAM 880.
> >
> > It basically:
> > . implements V4L2_CAP_STREAMING using videobuf;
> >
> > . re-implements V4L2_CAP_READWRITE using videobuf;
> >
> > . copies cam->udev->product to the card field of the v4l2_capability
> > struct. That gives more information to the users about the webcam;
> >
> > . moves the brightness setting code from before requesting a frame (in
> > read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> > executed only when the application requests a change in brightness and
> > not before every frame read;
> >
> > . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> > libv4l do not work.
> >
> > This patch fixes zr364xx for applications such as mplayer,
> > Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> > with zr364xx chip.
> >
> > Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> > ---
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-15 23:54 [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Lamarque Vieira Souza
2009-07-16 12:59 ` Antoine Jacquet
@ 2009-07-16 15:45 ` Mauro Carvalho Chehab
2009-07-16 15:56 ` Force driver to load (tcm825x) Jesko Schwarzer
` (2 more replies)
2009-07-20 23:46 ` [PATCH] Implement changing resolution on the fly " Lamarque Vieira Souza
2 siblings, 3 replies; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2009-07-16 15:45 UTC (permalink / raw)
To: Lamarque Vieira Souza; +Cc: Antoine Jacquet, linux-media, video4linux-list
Em Wed, 15 Jul 2009 20:54:55 -0300
Lamarque Vieira Souza <lamarque@gmail.com> escreveu:
> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> converting the driver to use videobuf. This version is synced with v4l-dvb as
> of 15/Jul/2009.
>
> Tested with Creative PC-CAM 880.
>
> It basically:
> . implements V4L2_CAP_STREAMING using videobuf;
>
> . re-implements V4L2_CAP_READWRITE using videobuf;
>
> . copies cam->udev->product to the card field of the v4l2_capability struct.
> That gives more information to the users about the webcam;
>
> . moves the brightness setting code from before requesting a frame (in
> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> executed only when the application requests a change in brightness and
> not before every frame read;
>
> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> libv4l do not work.
>
> This patch fixes zr364xx for applications such as mplayer,
> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> with zr364xx chip.
>
> Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> ---
>
> diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
> --- a/linux/drivers/media/video/zr364xx.c Sun Jul 05 19:08:55 2009 -0300
> +++ b/linux/drivers/media/video/zr364xx.c Wed Jul 15 20:50:34 2009 -0300
> @@ -1,5 +1,5 @@
> /*
> - * Zoran 364xx based USB webcam module version 0.72
> + * Zoran 364xx based USB webcam module version 0.73
> *
> * Allows you to use your USB webcam with V4L2 applications
> * This is still in heavy developpement !
> @@ -10,6 +10,8 @@
> * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
> * V4L2 version inspired by meye.c driver
> *
> + * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
> + *
Maybe the better example for it is em28xx-video, where we firstly used videobuf
on usb devices.
> +static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
> *buf)
> +{
> + DBG("%s\n", __func__);
> +
> + /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
> + * after running Skype on an AMD64 system. */
> + /*videobuf_waiton(&buf->vb, 0, 0);*/
Answering to your note, take a look at em28xx-video implementation:
/* We used to wait for the buffer to finish here, but this didn't work
because, as we were keeping the state as VIDEOBUF_QUEUED,
videobuf_queue_cancel marked it as finished for us.
(Also, it could wedge forever if the hardware was misconfigured.)
This should be safe; by the time we get here, the buffer isn't
queued anymore. If we ever start marking the buffers as
VIDEOBUF_ACTIVE, it won't be, though.
*/
spin_lock_irqsave(&dev->slock, flags);
if (dev->isoc_ctl.buf == buf)
dev->isoc_ctl.buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
> + if (pipe_info->state != 0) {
> + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
> + dev_err(&cam->udev->dev, "error submitting urb\n");
> + } else {
> + DBG("read pipe complete state 0\n");
> + }
Hmm... for the usb_submit_urb() call that happens during IRQ context (while
you're receiving stream), you need to use:
urb->status = usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC);
otherwise, you may get the errors that Antoine is reporting
Cheers,
Mauro
^ permalink raw reply [flat|nested] 21+ messages in thread* Force driver to load (tcm825x)
2009-07-16 15:45 ` Mauro Carvalho Chehab
@ 2009-07-16 15:56 ` Jesko Schwarzer
2009-07-16 16:42 ` [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Karicheri, Muralidharan
2009-07-16 20:09 ` Lamarque Vieira Souza
2 siblings, 0 replies; 21+ messages in thread
From: Jesko Schwarzer @ 2009-07-16 15:56 UTC (permalink / raw)
To: video4linux-list
Hello,
I am working to get the omap34xxcam with the tcm825x running. Currently I
was not successful in forcing the driver to load and register (in absence of
a real sensor). I do a probe when the driver starts and uncommented the i2c
things.
It fails when calling the
vidioc_int_g_priv()
Function in the device-register function of the "omap34xxcam.c".
How do I get it accepting the data ?
Is there any documentation to find?
Any hint would be perfect.
Kind regards
/Jesko
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 21+ messages in thread
* RE: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-16 15:45 ` Mauro Carvalho Chehab
2009-07-16 15:56 ` Force driver to load (tcm825x) Jesko Schwarzer
@ 2009-07-16 16:42 ` Karicheri, Muralidharan
2009-07-16 20:09 ` Lamarque Vieira Souza
2 siblings, 0 replies; 21+ messages in thread
From: Karicheri, Muralidharan @ 2009-07-16 16:42 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Lamarque Vieira Souza
Cc: Antoine Jacquet, linux-media@vger.kernel.org,
video4linux-list@redhat.com
Mauro,
Thanks. That was what I was thinking, but just want to see what issues I might face on the way. I am starting the work on DM6467 capture driver and you would be getting a patch soon for review in the mailing list.
Regards,
Murali Karicheri
Software Design Engineer
Texas Instruments Inc.
>-----Original Message-----
>From: linux-media-owner@vger.kernel.org [mailto:linux-media-
>owner@vger.kernel.org] On Behalf Of Mauro Carvalho Chehab
>Sent: Thursday, July 16, 2009 11:45 AM
>To: Lamarque Vieira Souza
>Cc: Antoine Jacquet; linux-media@vger.kernel.org; video4linux-
>list@redhat.com
>Subject: Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
>
>Em Wed, 15 Jul 2009 20:54:55 -0300
>Lamarque Vieira Souza <lamarque@gmail.com> escreveu:
>
>> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
>> converting the driver to use videobuf. This version is synced with v4l-
>dvb as
>> of 15/Jul/2009.
>>
>> Tested with Creative PC-CAM 880.
>>
>> It basically:
>> . implements V4L2_CAP_STREAMING using videobuf;
>>
>> . re-implements V4L2_CAP_READWRITE using videobuf;
>>
>> . copies cam->udev->product to the card field of the v4l2_capability
>struct.
>> That gives more information to the users about the webcam;
>>
>> . moves the brightness setting code from before requesting a frame (in
>> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
>> executed only when the application requests a change in brightness and
>> not before every frame read;
>>
>> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
>> libv4l do not work.
>>
>> This patch fixes zr364xx for applications such as mplayer,
>> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
>> with zr364xx chip.
>>
>> Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
>> ---
>>
>> diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
>> --- a/linux/drivers/media/video/zr364xx.c Sun Jul 05 19:08:55 2009 -
>0300
>> +++ b/linux/drivers/media/video/zr364xx.c Wed Jul 15 20:50:34 2009 -
>0300
>> @@ -1,5 +1,5 @@
>> /*
>> - * Zoran 364xx based USB webcam module version 0.72
>> + * Zoran 364xx based USB webcam module version 0.73
>> *
>> * Allows you to use your USB webcam with V4L2 applications
>> * This is still in heavy developpement !
>> @@ -10,6 +10,8 @@
>> * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c
>drivers
>> * V4L2 version inspired by meye.c driver
>> *
>> + * Some video buffer code by Lamarque based on s2255drv.c and vivi.c
>drivers.
>> + *
>
>Maybe the better example for it is em28xx-video, where we firstly used
>videobuf
>on usb devices.
>
>> +static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
>> *buf)
>> +{
>> + DBG("%s\n", __func__);
>> +
>> + /*Lamarque: is this really needed? Sometimes this blocks rmmod
>forever
>> + * after running Skype on an AMD64 system. */
>> + /*videobuf_waiton(&buf->vb, 0, 0);*/
>
>Answering to your note, take a look at em28xx-video implementation:
>
> /* We used to wait for the buffer to finish here, but this didn't
>work
> because, as we were keeping the state as VIDEOBUF_QUEUED,
> videobuf_queue_cancel marked it as finished for us.
> (Also, it could wedge forever if the hardware was
>misconfigured.)
>
> This should be safe; by the time we get here, the buffer isn't
> queued anymore. If we ever start marking the buffers as
> VIDEOBUF_ACTIVE, it won't be, though.
> */
> spin_lock_irqsave(&dev->slock, flags);
> if (dev->isoc_ctl.buf == buf)
> dev->isoc_ctl.buf = NULL;
> spin_unlock_irqrestore(&dev->slock, flags);
>
>> + if (pipe_info->state != 0) {
>> + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
>> + dev_err(&cam->udev->dev, "error submitting urb\n");
>> + } else {
>> + DBG("read pipe complete state 0\n");
>> + }
>
>Hmm... for the usb_submit_urb() call that happens during IRQ context
>(while
>you're receiving stream), you need to use:
> urb->status = usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC);
>
>otherwise, you may get the errors that Antoine is reporting
>
>
>
>Cheers,
>Mauro
>--
>To unsubscribe from this list: send the line "unsubscribe linux-media" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-16 15:45 ` Mauro Carvalho Chehab
2009-07-16 15:56 ` Force driver to load (tcm825x) Jesko Schwarzer
2009-07-16 16:42 ` [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Karicheri, Muralidharan
@ 2009-07-16 20:09 ` Lamarque Vieira Souza
2009-07-17 23:50 ` Antoine Jacquet
2 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-16 20:09 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Antoine Jacquet, linux-media, video4linux-list
Em Quinta-feira 16 Julho 2009, Mauro Carvalho Chehab escreveu:
> Em Wed, 15 Jul 2009 20:54:55 -0300
>
> Lamarque Vieira Souza <lamarque@gmail.com> escreveu:
> > This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> > converting the driver to use videobuf. This version is synced with
> > v4l-dvb as of 15/Jul/2009.
> >
> > Tested with Creative PC-CAM 880.
> >
> > It basically:
> > . implements V4L2_CAP_STREAMING using videobuf;
> >
> > . re-implements V4L2_CAP_READWRITE using videobuf;
> >
> > . copies cam->udev->product to the card field of the v4l2_capability
> > struct. That gives more information to the users about the webcam;
> >
> > . moves the brightness setting code from before requesting a frame (in
> > read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> > executed only when the application requests a change in brightness and
> > not before every frame read;
> >
> > . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> > libv4l do not work.
> >
> > This patch fixes zr364xx for applications such as mplayer,
> > Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> > with zr364xx chip.
> >
> > Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> > ---
> >
> > diff -r c300798213a9 linux/drivers/media/video/zr364xx.c
> > --- a/linux/drivers/media/video/zr364xx.c Sun Jul 05 19:08:55 2009 -0300
> > +++ b/linux/drivers/media/video/zr364xx.c Wed Jul 15 20:50:34 2009 -0300
> > @@ -1,5 +1,5 @@
> > /*
> > - * Zoran 364xx based USB webcam module version 0.72
> > + * Zoran 364xx based USB webcam module version 0.73
> > *
> > * Allows you to use your USB webcam with V4L2 applications
> > * This is still in heavy developpement !
> > @@ -10,6 +10,8 @@
> > * Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c
> > drivers * V4L2 version inspired by meye.c driver
> > *
> > + * Some video buffer code by Lamarque based on s2255drv.c and vivi.c
> > drivers. + *
>
> Maybe the better example for it is em28xx-video, where we firstly used
> videobuf on usb devices.
I will take a look at em28xx-video. I used s2255drv.c and vivi.c because
their code organization are similar to zr364xx.c, so it was easier to know
what to do.
> > +static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
> > *buf)
> > +{
> > + DBG("%s\n", __func__);
> > +
> > + /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
> > + * after running Skype on an AMD64 system. */
> > + /*videobuf_waiton(&buf->vb, 0, 0);*/
>
> Answering to your note, take a look at em28xx-video implementation:
>
> /* We used to wait for the buffer to finish here, but this didn't
> work because, as we were keeping the state as VIDEOBUF_QUEUED,
> videobuf_queue_cancel marked it as finished for us.
> (Also, it could wedge forever if the hardware was
> misconfigured.)
>
> This should be safe; by the time we get here, the buffer isn't
> queued anymore. If we ever start marking the buffers as
> VIDEOBUF_ACTIVE, it won't be, though.
> */
> spin_lock_irqsave(&dev->slock, flags);
> if (dev->isoc_ctl.buf == buf)
> dev->isoc_ctl.buf = NULL;
> spin_unlock_irqrestore(&dev->slock, flags);
Yes, the comment answers my question. There is no similar code in zr364xx.c
like the one above. zr364xx_camera does not have a member with zr364xxx_buffer
type (the equivalent type of dev->isoc_ctl.buf).
> > + if (pipe_info->state != 0) {
> > + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
> > + dev_err(&cam->udev->dev, "error submitting urb\n");
> > + } else {
> > + DBG("read pipe complete state 0\n");
> > + }
>
> Hmm... for the usb_submit_urb() call that happens during IRQ context
> (while you're receiving stream), you need to use:
> urb->status = usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC);
>
> otherwise, you may get the errors that Antoine is reporting
Ok, changed to GPF_ATOMIC. Could someone test this for me since I was not
able to reproduce this problem? The new patch is here
http://bach.metasys.com.br/~lamarque/zr364xx/zr364xx.c-streaming.patch-v4l-
dvb-20090716 . I upload it to avoid bloating the mailing-list with a 40k
patch.
I have computer here with dual core processor but no display. I need to get a
DVI <-> VGA adaptor to plug my DVI LCD on it, when I get one I am going to
test the changes with SMP enabled.
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-16 20:09 ` Lamarque Vieira Souza
@ 2009-07-17 23:50 ` Antoine Jacquet
0 siblings, 0 replies; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-17 23:50 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
Lamarque Vieira Souza wrote:
> Em Quinta-feira 16 Julho 2009, Mauro Carvalho Chehab escreveu:
>> Em Wed, 15 Jul 2009 20:54:55 -0300
[...]
>>> + if (pipe_info->state != 0) {
>>> + if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL))
>>> + dev_err(&cam->udev->dev, "error submitting urb\n");
>>> + } else {
>>> + DBG("read pipe complete state 0\n");
>>> + }
>> Hmm... for the usb_submit_urb() call that happens during IRQ context
>> (while you're receiving stream), you need to use:
>> urb->status = usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC);
>>
>> otherwise, you may get the errors that Antoine is reporting
>
> Ok, changed to GPF_ATOMIC. Could someone test this for me since I was not
> able to reproduce this problem? The new patch is here
> http://bach.metasys.com.br/~lamarque/zr364xx/zr364xx.c-streaming.patch-v4l-
> dvb-20090716 . I upload it to avoid bloating the mailing-list with a 40k
> patch.
I confirm it fixes the issue.
I will upload the patch to my branch and send a pull request to Mauro.
Thanks and best regards,
Antoine
--
Antoine "Royale" Jacquet
http://royale.zerezo.com
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-15 23:54 [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Lamarque Vieira Souza
2009-07-16 12:59 ` Antoine Jacquet
2009-07-16 15:45 ` Mauro Carvalho Chehab
@ 2009-07-20 23:46 ` Lamarque Vieira Souza
2009-07-21 14:29 ` Antoine Jacquet
2 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-20 23:46 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
This patch implements changing resolution in zr364xx_vidioc_s_fmt_vid_cap for
zr364xx driver. This version is synced with v4l-dvb as of 20/Jul/2009. Tested
with Creative PC-CAM 880.
OBS: I had to increase MAX_FRAME_SIZE to prevent a hard crash in my notebook
(caps lock blinking) when testing with mplayer, which automatically sets
resolution to the maximum (640x480). Maybe we should add code to auto-detect
frame size to prevent this kind of crash in the future.
Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
---
diff -r 1cb6f19d2c9d linux/drivers/media/video/zr364xx.c
--- a/linux/drivers/media/video/zr364xx.c Sun Jul 19 18:03:23 2009 -0300
+++ b/linux/drivers/media/video/zr364xx.c Mon Jul 20 20:20:21 2009 -0300
@@ -43,14 +43,14 @@
/* Version Information */
#define DRIVER_VERSION "v0.73"
-#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
+#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
#define FRAMES 1
-#define MAX_FRAME_SIZE 100000
+#define MAX_FRAME_SIZE 200000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
@@ -734,7 +734,7 @@
strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
sizeof(cap->bus_info));
- cap->version = ZR364_VERSION_CODE;
+ cap->version = ZR364XX_VERSION_CODE;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
@@ -874,9 +874,14 @@
return -EINVAL;
}
+ if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
+ !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ }
+
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
@@ -907,7 +912,6 @@
return 0;
}
-/* Lamarque TODO: implement changing resolution on the fly */
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -915,6 +919,7 @@
struct videobuf_queue *q = &cam->vb_vidq;
char pixelformat_name[5];
int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+ int i;
if (ret < 0)
return ret;
@@ -927,15 +932,55 @@
goto out;
}
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
+ if (res_check(cam)) {
+ DBG("%s can't change format after started\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
+ dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+ cam->width, cam->height);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
cam->vb_vidq.field = f->fmt.pix.field;
cam->mode.color = V4L2_PIX_FMT_JPEG;
+
+ if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
+ mode = 1;
+ else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
+ mode = 2;
+ else
+ mode = 0;
+
+ m0d1[0] = mode;
+ m1[2].value = 0xf000 + mode;
+ m2[1].value = 0xf000 + mode;
+ header2[437] = cam->height / 256;
+ header2[438] = cam->height % 256;
+ header2[439] = cam->width / 256;
+ header2[440] = cam->width % 256;
+
+ for (i = 0; init[cam->method][i].size != -1; i++) {
+ ret =
+ send_control_msg(cam->udev, 1, init[cam->method][i].value,
+ 0, init[cam->method][i].bytes,
+ init[cam->method][i].size);
+ if (ret < 0) {
+ dev_err(&cam->udev->dev,
+ "error during resolution change sequence: %d\n", i);
+ goto out;
+ }
+ }
+
+ /* Added some delay here, since opening/closing the camera quickly,
+ * like Ekiga does during its startup, can crash the webcam
+ */
+ mdelay(100);
+ cam->skip = 2;
ret = 0;
out:
@@ -1123,6 +1168,7 @@
cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
cam->buffer.frame[j].cur_size = 0;
}
+ cam->b_acquire = 1;
return 0;
}
@@ -1165,7 +1211,6 @@
res = videobuf_streamon(&cam->vb_vidq);
if (res == 0) {
zr364xx_start_acquire(cam);
- cam->b_acquire = 1;
} else {
res_free(cam);
}
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-20 23:46 ` [PATCH] Implement changing resolution on the fly " Lamarque Vieira Souza
@ 2009-07-21 14:29 ` Antoine Jacquet
2009-07-21 15:14 ` Lamarque Vieira Souza
0 siblings, 1 reply; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-21 14:29 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
> This patch implements changing resolution in zr364xx_vidioc_s_fmt_vid_cap for
> zr364xx driver. This version is synced with v4l-dvb as of 20/Jul/2009. Tested
> with Creative PC-CAM 880.
Nice, I successfully tested your patch with 2 compatible webcams.
From the users feedbacks I had before, it seems that some devices do
not support the 640x480 resolution, but I was not able to verify this
myself.
This is the only concern I have, since some users may think the driver
is not working if the application automatically switches to the maximum
resolution with an incompatible device.
> OBS: I had to increase MAX_FRAME_SIZE to prevent a hard crash in my notebook
> (caps lock blinking) when testing with mplayer, which automatically sets
> resolution to the maximum (640x480). Maybe we should add code to auto-detect
> frame size to prevent this kind of crash in the future.
Yes, I also had this issue before. I don't know what is the good
approach to determine the best size with JPEG compression.
I will push your changes to my tree and send a pull request to Mauro later.
Regards,
Antoine
--
Antoine "Royale" Jacquet
http://royale.zerezo.com
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-21 14:29 ` Antoine Jacquet
@ 2009-07-21 15:14 ` Lamarque Vieira Souza
2009-07-21 22:42 ` Lamarque Vieira Souza
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-21 15:14 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Em Terça-feira 21 Julho 2009, Antoine Jacquet escreveu:
> Hi,
Hi,
> > This patch implements changing resolution in zr364xx_vidioc_s_fmt_vid_cap
> > for zr364xx driver. This version is synced with v4l-dvb as of
> > 20/Jul/2009. Tested with Creative PC-CAM 880.
>
> Nice, I successfully tested your patch with 2 compatible webcams.
> From the users feedbacks I had before, it seems that some devices do
> not support the 640x480 resolution, but I was not able to verify this
> myself.
> This is the only concern I have, since some users may think the driver
> is not working if the application automatically switches to the maximum
> resolution with an incompatible device.
Maybe we should add a quirk list to prevent such cases or if send_control_msg
returns error in such cases I can change the code to revert the change and
keep the old resolution.
> > OBS: I had to increase MAX_FRAME_SIZE to prevent a hard crash in my
> > notebook (caps lock blinking) when testing with mplayer, which
> > automatically sets resolution to the maximum (640x480). Maybe we should
> > add code to auto-detect frame size to prevent this kind of crash in the
> > future.
>
> Yes, I also had this issue before. I don't know what is the good
> approach to determine the best size with JPEG compression.
The driver reads data from USB port in 4096-bytes chunks, so before adding
the data to frm->lpvbits we could verify if frm->lpvbits has enough space to
hold it. If there is no enough space we can dynamically increase frm->lpvbits.
In user space that can be done using realloc, I just do not know if there is a
similar function in kernel space. OBS: frm->lpvbits had be increased without
loosing the old data and of course we should have a upper limit, maybe 640 x
480 * 3 (3 bytes per pixel) = 921600 bytes.
> I will push your changes to my tree and send a pull request to Mauro later.
Ok, thanks.
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-21 15:14 ` Lamarque Vieira Souza
@ 2009-07-21 22:42 ` Lamarque Vieira Souza
2009-07-22 19:31 ` Antoine Jacquet
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-21 22:42 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
I have made some changes to the patch:
. added code to print an error message when buffer is too small to hold frame
data, that is better than just a hard crash. Tested using MAX_FRAME_SIZE =
50000, lots of error messages appeared in /var/log/messages but no crash.
. removed line "f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;" in
zr364xx_vidioc_try_fmt_vid_cap, it should not be there.
. changes to improve performance (or at least not hurt it): removed some
unneeded debug messages; added macro FULL_DEBUG to enable debug messages in
performance critical places, this macro is disabled by default; removed "if
(frm->lpvbits == NULL)..." in zr364xx_read_video_callback because after
analisying the source code I concluded it will always results to false, so it
is not needed.
. some small code reorganization.
There is an incremental version of the last patch I sent in
http://bach.metasys.com.br/~lamarque/zr364xx/zr364xx.c-resolution.patch-
incremental-v4l-dvb-20090721
Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
---
diff -r 6477aa1782d5 linux/drivers/media/video/zr364xx.c
--- a/linux/drivers/media/videon/zr364xx.c Tue Jul 21 09:17:24 2009 -0300
+++ b/linux/drivers/media/video/zr364xx.c Tue Jul 21 19:00:52 2009 -0300
@@ -44,14 +44,14 @@
/* Version Information */
#define DRIVER_VERSION "v0.73"
-#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
+#define ZR364XX_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
#define FRAMES 1
-#define MAX_FRAME_SIZE 100000
+#define MAX_FRAME_SIZE 200000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
@@ -67,6 +67,13 @@
} \
} while (0)
+/*#define FULL_DEBUG 1*/
+#ifdef FULL_DEBUG
+#define _DBG DBG
+#else
+#define _DBG(fmt, args...)
+#endif
+
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
#define METHOD0 0
@@ -376,7 +383,7 @@
static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
*buf)
{
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (in_interrupt())
BUG();
@@ -429,7 +436,7 @@
vb);
struct zr364xx_camera *cam = vq->priv_data;
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &cam->vidq.active);
@@ -441,7 +448,7 @@
struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
vb);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
free_buffer(vq, buf);
}
@@ -463,7 +470,7 @@
{
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -583,7 +590,7 @@
int i = 0;
unsigned char *ptr = NULL;
- /*DBG("buffer to user\n");*/
+ _DBG("buffer to user\n");
idx = cam->cur_frame;
frm = &cam->buffer.frame[idx];
@@ -601,12 +608,6 @@
return -EINVAL;
}
- if (frm->lpvbits == NULL) {
- DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
- frm, cam, idx);
- return -ENOMEM;
- }
-
psrc = (u8 *)pipe_info->transfer_buffer;
ptr = pdest = frm->lpvbits;
@@ -614,7 +615,7 @@
frm->ulState = ZR364XX_READ_FRAME;
frm->cur_size = 0;
- DBG("jpeg header, ");
+ _DBG("jpeg header, ");
memcpy(ptr, header1, sizeof(header1));
ptr += sizeof(header1);
header3 = 0;
@@ -632,21 +633,28 @@
memcpy(ptr, psrc + 128,
purb->actual_length - 128);
ptr += purb->actual_length - 128;
- DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ _DBG("header : %d %d %d %d %d %d %d %d %d\n",
psrc[0], psrc[1], psrc[2],
psrc[3], psrc[4], psrc[5],
psrc[6], psrc[7], psrc[8]);
frm->cur_size = ptr - pdest;
} else {
- pdest += frm->cur_size;
- memcpy(pdest, psrc, purb->actual_length);
- frm->cur_size += purb->actual_length;
+ if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
+ dev_info(&cam->udev->dev,
+ "%s: buffer (%d bytes) too small to hold "
+ "frame data\n",
+ __func__, MAX_FRAME_SIZE);
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
}
- /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
purb->actual_length);*/
if (purb->actual_length < pipe_info->transfer_size) {
- DBG("****************Buffer[%d]full*************\n", idx);
+ _DBG("****************Buffer[%d]full*************\n", idx);
cam->last_frame = cam->cur_frame;
cam->cur_frame++;
/* end of system frame ring buffer, start at zero */
@@ -681,7 +689,7 @@
if (cam->skip)
cam->skip--;
else {
- DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
frm->cur_size,
pdest[0], pdest[1], pdest[2], pdest[3],
pdest[4], pdest[5], pdest[6], pdest[7]);
@@ -708,7 +716,7 @@
}
/* it's free, grab it */
cam->resources = 1;
- DBG("res: get\n");
+ _DBG("res: get\n");
mutex_unlock(&cam->lock);
return 1;
}
@@ -723,7 +731,7 @@
mutex_lock(&cam->lock);
cam->resources = 0;
mutex_unlock(&cam->lock);
- DBG("res: put\n");
+ _DBG("res: put\n");
}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
@@ -735,7 +743,7 @@
strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
sizeof(cap->bus_info));
- cap->version = ZR364_VERSION_CODE;
+ cap->version = ZR364XX_VERSION_CODE;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
@@ -875,9 +883,13 @@
return -EINVAL;
}
+ if (!(f->fmt.pix.width == 160 && f->fmt.pix.height == 120) &&
+ !(f->fmt.pix.width == 640 && f->fmt.pix.height == 480)) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ }
+
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
@@ -908,7 +920,6 @@
return 0;
}
-/* Lamarque TODO: implement changing resolution on the fly */
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -916,6 +927,7 @@
struct videobuf_queue *q = &cam->vb_vidq;
char pixelformat_name[5];
int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+ int i;
if (ret < 0)
return ret;
@@ -928,15 +940,55 @@
goto out;
}
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = cam->width;
- f->fmt.pix.height = cam->height;
+ if (res_check(cam)) {
+ DBG("%s can't change format after started\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
+ dev_info(&cam->udev->dev, "%s: %dx%d mode selected\n", __func__,
+ cam->width, cam->height);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
cam->vb_vidq.field = f->fmt.pix.field;
cam->mode.color = V4L2_PIX_FMT_JPEG;
+
+ if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120)
+ mode = 1;
+ else if (f->fmt.pix.width == 640 && f->fmt.pix.height == 480)
+ mode = 2;
+ else
+ mode = 0;
+
+ m0d1[0] = mode;
+ m1[2].value = 0xf000 + mode;
+ m2[1].value = 0xf000 + mode;
+ header2[437] = cam->height / 256;
+ header2[438] = cam->height % 256;
+ header2[439] = cam->width / 256;
+ header2[440] = cam->width % 256;
+
+ for (i = 0; init[cam->method][i].size != -1; i++) {
+ ret =
+ send_control_msg(cam->udev, 1, init[cam->method][i].value,
+ 0, init[cam->method][i].bytes,
+ init[cam->method][i].size);
+ if (ret < 0) {
+ dev_err(&cam->udev->dev,
+ "error during resolution change sequence: %d\n", i);
+ goto out;
+ }
+ }
+
+ /* Added some delay here, since opening/closing the camera quickly,
+ * like Ekiga does during its startup, can crash the webcam
+ */
+ mdelay(100);
+ cam->skip = 2;
ret = 0;
out:
@@ -973,7 +1025,7 @@
{
int rc;
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
rc = videobuf_qbuf(&cam->vb_vidq, p);
return rc;
}
@@ -984,7 +1036,7 @@
{
int rc;
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
return rc;
}
@@ -996,7 +1048,7 @@
int pipe;
pipe_info = purb->context;
- /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ _DBG("%s %p, status %d\n", __func__, purb, purb->status);
if (pipe_info == NULL) {
printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
return;
@@ -1107,7 +1159,6 @@
pipe_info->stream_urb = NULL;
}
}
- DBG("stop read pipe\n");
return;
}
@@ -1124,6 +1175,7 @@
cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
cam->buffer.frame[j].cur_size = 0;
}
+ cam->b_acquire = 1;
return 0;
}
@@ -1166,11 +1218,9 @@
res = videobuf_streamon(&cam->vb_vidq);
if (res == 0) {
zr364xx_start_acquire(cam);
- cam->b_acquire = 1;
} else {
res_free(cam);
}
- DBG("%s: %d\n", __func__, res);
return res;
}
@@ -1282,8 +1332,6 @@
/* release transfer buffer */
kfree(cam->pipe->transfer_buffer);
cam->pipe->transfer_buffer = NULL;
-
- DBG("%s\n", __func__);
mutex_unlock(&cam->open_lock);
kfree(cam);
cam = NULL;
@@ -1364,7 +1412,7 @@
{
struct zr364xx_camera *cam = video_drvdata(file);
struct videobuf_queue *q = &cam->vb_vidq;
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return POLLERR;
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-21 22:42 ` Lamarque Vieira Souza
@ 2009-07-22 19:31 ` Antoine Jacquet
2009-07-22 19:54 ` Lamarque Vieira Souza
0 siblings, 1 reply; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-22 19:31 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
Lamarque Vieira Souza wrote:
> I have made some changes to the patch:
Since I already included your previous patch and sent a pull request to
Mauro, could you send a patch against my current tree:
http://linuxtv.org/hg/~ajacquet/zr364xx/
Thanks,
Antoine
--
Antoine "Royale" Jacquet
http://royale.zerezo.com
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-22 19:31 ` Antoine Jacquet
@ 2009-07-22 19:54 ` Lamarque Vieira Souza
2009-07-22 23:58 ` Antoine Jacquet
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-22 19:54 UTC (permalink / raw)
To: Antoine Jacquet; +Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Em Quarta-feira 22 Julho 2009, Antoine Jacquet escreveu:
> Hi,
>
> Lamarque Vieira Souza wrote:
> > I have made some changes to the patch:
>
> Since I already included your previous patch and sent a pull request to
> Mauro, could you send a patch against my current tree:
> http://linuxtv.org/hg/~ajacquet/zr364xx/
>
> Thanks,
>
> Antoine
Here it is
Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
---
diff -r ebb57057cf4d linux/drivers/media/video/zr364xx.c
--- a/linux/drivers/media/video/zr364xx.c Mon Jul 20 20:46:42 2009 -0300
+++ b/linux/drivers/media/video/zr364xx.c Wed Jul 22 16:52:30 2009 -0300
@@ -67,6 +67,13 @@
} \
} while (0)
+/*#define FULL_DEBUG 1*/
+#ifdef FULL_DEBUG
+#define _DBG DBG
+#else
+#define _DBG(fmt, args...)
+#endif
+
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
#define METHOD0 0
@@ -376,7 +383,7 @@
static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
*buf)
{
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (in_interrupt())
BUG();
@@ -429,7 +436,7 @@
vb);
struct zr364xx_camera *cam = vq->priv_data;
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &cam->vidq.active);
@@ -441,7 +448,7 @@
struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
vb);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
free_buffer(vq, buf);
}
@@ -463,7 +470,7 @@
{
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -583,7 +590,7 @@
int i = 0;
unsigned char *ptr = NULL;
- /*DBG("buffer to user\n");*/
+ _DBG("buffer to user\n");
idx = cam->cur_frame;
frm = &cam->buffer.frame[idx];
@@ -601,12 +608,6 @@
return -EINVAL;
}
- if (frm->lpvbits == NULL) {
- DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
- frm, cam, idx);
- return -ENOMEM;
- }
-
psrc = (u8 *)pipe_info->transfer_buffer;
ptr = pdest = frm->lpvbits;
@@ -614,7 +615,7 @@
frm->ulState = ZR364XX_READ_FRAME;
frm->cur_size = 0;
- DBG("jpeg header, ");
+ _DBG("jpeg header, ");
memcpy(ptr, header1, sizeof(header1));
ptr += sizeof(header1);
header3 = 0;
@@ -632,21 +633,28 @@
memcpy(ptr, psrc + 128,
purb->actual_length - 128);
ptr += purb->actual_length - 128;
- DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ _DBG("header : %d %d %d %d %d %d %d %d %d\n",
psrc[0], psrc[1], psrc[2],
psrc[3], psrc[4], psrc[5],
psrc[6], psrc[7], psrc[8]);
frm->cur_size = ptr - pdest;
} else {
- pdest += frm->cur_size;
- memcpy(pdest, psrc, purb->actual_length);
- frm->cur_size += purb->actual_length;
+ if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) {
+ dev_info(&cam->udev->dev,
+ "%s: buffer (%d bytes) too small to hold "
+ "frame data. Discarding frame data.\n",
+ __func__, MAX_FRAME_SIZE);
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
}
- /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ /*_DBG("cur_size %lu urb size %d\n", frm->cur_size,
purb->actual_length);*/
if (purb->actual_length < pipe_info->transfer_size) {
- DBG("****************Buffer[%d]full*************\n", idx);
+ _DBG("****************Buffer[%d]full*************\n", idx);
cam->last_frame = cam->cur_frame;
cam->cur_frame++;
/* end of system frame ring buffer, start at zero */
@@ -681,7 +689,7 @@
if (cam->skip)
cam->skip--;
else {
- DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ _DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
frm->cur_size,
pdest[0], pdest[1], pdest[2], pdest[3],
pdest[4], pdest[5], pdest[6], pdest[7]);
@@ -708,7 +716,7 @@
}
/* it's free, grab it */
cam->resources = 1;
- DBG("res: get\n");
+ _DBG("res: get\n");
mutex_unlock(&cam->lock);
return 1;
}
@@ -723,7 +731,7 @@
mutex_lock(&cam->lock);
cam->resources = 0;
mutex_unlock(&cam->lock);
- DBG("res: put\n");
+ _DBG("res: put\n");
}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
@@ -882,7 +890,6 @@
}
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
@@ -1018,7 +1025,7 @@
{
int rc;
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
rc = videobuf_qbuf(&cam->vb_vidq, p);
return rc;
}
@@ -1029,7 +1036,7 @@
{
int rc;
struct zr364xx_camera *cam = video_drvdata(file);
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
return rc;
}
@@ -1041,7 +1048,7 @@
int pipe;
pipe_info = purb->context;
- /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ _DBG("%s %p, status %d\n", __func__, purb, purb->status);
if (pipe_info == NULL) {
printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
return;
@@ -1152,7 +1159,6 @@
pipe_info->stream_urb = NULL;
}
}
- DBG("stop read pipe\n");
return;
}
@@ -1215,7 +1221,6 @@
} else {
res_free(cam);
}
- DBG("%s: %d\n", __func__, res);
return res;
}
@@ -1327,8 +1332,6 @@
/* release transfer buffer */
kfree(cam->pipe->transfer_buffer);
cam->pipe->transfer_buffer = NULL;
-
- DBG("%s\n", __func__);
mutex_unlock(&cam->open_lock);
kfree(cam);
cam = NULL;
@@ -1409,7 +1412,7 @@
{
struct zr364xx_camera *cam = video_drvdata(file);
struct videobuf_queue *q = &cam->vb_vidq;
- DBG("%s\n", __func__);
+ _DBG("%s\n", __func__);
if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return POLLERR;
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement changing resolution on the fly for zr364xx driver
2009-07-22 19:54 ` Lamarque Vieira Souza
@ 2009-07-22 23:58 ` Antoine Jacquet
0 siblings, 0 replies; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-22 23:58 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
Lamarque Vieira Souza wrote:
> Em Quarta-feira 22 Julho 2009, Antoine Jacquet escreveu:
>> Hi,
>>
>> Lamarque Vieira Souza wrote:
>>> I have made some changes to the patch:
>> Since I already included your previous patch and sent a pull request to
>> Mauro, could you send a patch against my current tree:
>> http://linuxtv.org/hg/~ajacquet/zr364xx/
>>
>> Thanks,
>>
>> Antoine
>
> Here it is
Thanks, I pushed the patch to my tree.
Sorry BTW, I just noticed the incremental version was already in your
first email.
Regards,
Antoine
--
Antoine "Royale" Jacquet
http://royale.zerezo.com
^ permalink raw reply [flat|nested] 21+ messages in thread
* Patch implementing V4L2_CAP_STREAMING for zr364xx driver
@ 2009-03-25 23:25 Lamarque Vieira Souza
2009-03-27 18:39 ` Lamarque Vieira Souza
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-03-25 23:25 UTC (permalink / raw)
To: Antoine Jacquet, linux-media; +Cc: Mauro Carvalho Chehab, video4linux-list
[-- Attachment #1: Type: text/plain, Size: 1282 bytes --]
Hi,
I have implemented V4L2_CAP_STREAMING for the zr364xx driver (see the
attached file). Could you review the code for me? My
Creative PC-CAM 880 works, but I do not have any other webcam to test the
code. Besides the streaming implementation the patch also does:
. re-implement V4L2_CAP_READWRITE using videobuf.
. copy cam->udev->product to the card field of the v4l2_capability struct.
That gives more information to the users about the webcam.
. move the brightness setting code from before requesting a frame (in
read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
executed only when the application request a change in brightness and not
before every frame read. Is there any reason to set the brightness before
every frame read?
. comment part of zr364xx_vidioc_try_fmt_vid_cap. Skype + libv4l do not work
if it is there and libv4's maintainer told me it is a driver bug, so I fix it.
This patch is needed for applications such as mplayer, Kopete+libv4l and
Skype+libv4l can make use of the webcam that comes with zr364xx chip. The
patch is big, if you need it splitted into small patches I can do it.
Best regards,
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
[-- Attachment #2: zr364xx.c-streaming.patch-2.6.29-20090325 --]
[-- Type: text/x-patch, Size: 40250 bytes --]
--- linux-2.6.29/drivers/media/video/zr364xx.c 2009-03-25 19:06:37.241552912 -0300
+++ linux-2.6.29-lvs/drivers/media/video/zr364xx.c 2009-03-25 19:25:58.981551627 -0300
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv driver.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,7 +27,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -36,23 +37,33 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
+#define DRIVER_VERSION "v0.73"
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
+#define FRAMES 1
#define MAX_FRAME_SIZE 100000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
/* Init methods, need to find nicer names for these
@@ -101,24 +112,96 @@ static struct usb_device_id device_table
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE, ZR364XX_READ_FRAME*/
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 transfer_flags;;
+ u32 state;
+ u32 prev_state;
+ u32 urb_size;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+ u32 priority_set;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt * fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -272,139 +355,116 @@ static unsigned char header2[] = {
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
-/********************/
-/* V4L2 integration */
-/********************/
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
-
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
-
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
-
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
-
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
+{
+ DBG("%s\n", __func__);
+
+ /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
+ * after running Skype on an AMD64 system. */
+ /*videobuf_waiton(&buf->vb, 0, 0);*/
+
+ if (in_interrupt())
+ BUG();
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ? cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
}
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
}
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ DBG("%s\n", __func__);
- return size;
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
}
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, vb);
+
+ DBG("%s\n", __func__);
+ free_buffer(vq, buf);
+}
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
+
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
+ struct zr364xx_camera *cam = video_drvdata(file);
- DBG("zr364xx_read: read %d bytes.", (int) count);
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -412,22 +472,268 @@ static ssize_t zr364xx_read(struct file
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count, (int) *ppos);
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
+
+ return 0;
+}
+
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam, struct zr364xx_buffer *buf, int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
+}
+
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ /*DBG("buffer to user\n");*/
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16*)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ if (frm->lpvbits == NULL) {
+ DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
+ frm, cam, idx);
+ return -ENOMEM;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ }
+ else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ /*DBG("cur_size %lu urb size %d\n", frm->cur_size, purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ }
+ else if (cam->b_acquire)
+ {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n", frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
- return count;
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
}
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
+}
+
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct zr364xx_camera *cam = video_drvdata(file);
+
memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info));
+ cap->version = ZR364_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
return 0;
}
@@ -461,12 +767,11 @@ static int zr364xx_vidioc_s_input(struct
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -475,7 +780,7 @@ static int zr364xx_vidioc_queryctrl(stru
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -487,36 +792,42 @@ static int zr364xx_vidioc_queryctrl(stru
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -535,28 +846,41 @@ static int zr364xx_vidioc_enum_fmt_vid_c
f->index = 0;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__, decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
+ }
+
+ /* Lamarque 25/03/2009: Skype + libv4l do not work if we return -EINVAL here. */
+ /*if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE) {
+ DBG("%s: unsupported field value %d\n",__func__, f->fmt.pix.field);
return -EINVAL;
+ }*/
+
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -564,24 +888,24 @@ static int zr364xx_vidioc_try_fmt_vid_ca
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), f->fmt.pix.field);
return 0;
}
static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -592,23 +916,26 @@ static int zr364xx_vidioc_g_fmt_vid_cap(
return 0;
}
+/* Lamarque TODO: implement changing resolution on the fly */
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+
+ if (ret < 0)
+ return (ret);
+
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -616,19 +943,251 @@ static int zr364xx_vidioc_s_fmt_vid_cap(
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
- DBG("ok!");
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int pipe;
+
+ pipe_info = purb->context;
+ /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+ if (purb->status != 0) {
+ DBG("_%s: err status = %d\n", __func__, purb->status);
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 || purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+
+ pipe_info->err_count = 0;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ dev_err(&cam->udev->dev, "error submitting urb\n");
+ usb_free_urb(pipe_info->stream_urb);
+ }
+ } else {
+ DBG("read pipe complete state 0\n");
+ }
+ return;
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->priority_set = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ pipe_info->urb_size = sizeof(pipe_info->stream_urb);
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0) {
+ pipe_info->state = 0;
+ pipe_info->prev_state = 1;
+ }
+
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ DBG("stop read pipe\n");
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ cam->b_acquire = 1;
+ } else {
+ res_free(cam);
+ }
+ DBG("%s: %d\n", __func__, res);
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -637,28 +1196,19 @@ static int zr364xx_vidioc_streamoff(stru
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -674,6 +1224,14 @@ static int zr364xx_open(struct file *fil
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -682,28 +1240,70 @@ static int zr364xx_open(struct file *fil
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+
+ DBG("%s\n", __func__);
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -726,40 +1326,43 @@ static int zr364xx_release(struct file *
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_mmap: %ld\n", size);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- if (vdev == NULL)
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
- cam = video_get_drvdata(vdev);
-
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
}
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- return 0;
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -768,6 +1371,7 @@ static const struct v4l2_file_operations
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -784,6 +1388,10 @@ static const struct v4l2_ioctl_ops zr364
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -799,15 +1407,75 @@ static struct video_device zr364xx_templ
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n");
+ break;
+ }
+ }
+
+ if ( i == 0 ) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ return -ENOMEM;
+ }
+ else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -829,19 +1497,13 @@ static int zr364xx_probe(struct usb_inte
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -868,21 +1530,48 @@ static int zr364xx_probe(struct usb_inte
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ zr364xx_board_init(cam);
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -892,15 +1581,13 @@ static int zr364xx_probe(struct usb_inte
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
if (cam->vdev)
video_unregister_device(cam->vdev);
cam->vdev = NULL;
- kfree(cam->buffer);
- if (cam->framebuf)
- vfree(cam->framebuf);
- kfree(cam);
+ zr364xx_destroy(cam);
}
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: Patch implementing V4L2_CAP_STREAMING for zr364xx driver
@ 2009-03-27 18:39 ` Lamarque Vieira Souza
2009-03-28 9:34 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-03-27 18:39 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Antoine Jacquet, linux-media, video4linux-list
[-- Attachment #1: Type: text/plain, Size: 2892 bytes --]
Here is the patch with the modifications you asked.
Em Friday 27 March 2009, Mauro Carvalho Chehab escreveu:
> On Wed, 25 Mar 2009 20:25:10 -0300
>
> Lamarque Vieira Souza <lamarque@gmail.com> wrote:
> > Hi,
> >
> > I have implemented V4L2_CAP_STREAMING for the zr364xx driver (see
> > the attached file). Could you review the code for me? My
> > Creative PC-CAM 880 works, but I do not have any other webcam to test the
> > code. Besides the streaming implementation the patch also does:
> >
> > . re-implement V4L2_CAP_READWRITE using videobuf.
> >
> > . copy cam->udev->product to the card field of the v4l2_capability
> > struct. That gives more information to the users about the webcam.
> >
> > . move the brightness setting code from before requesting a frame (in
> > read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> > executed only when the application request a change in brightness and not
> > before every frame read. Is there any reason to set the brightness before
> > every frame read?
> >
> > . comment part of zr364xx_vidioc_try_fmt_vid_cap. Skype + libv4l do not
> > work if it is there and libv4's maintainer told me it is a driver bug, so
> > I fix it.
> >
> > This patch is needed for applications such as mplayer, Kopete+libv4l and
> > Skype+libv4l can make use of the webcam that comes with zr364xx chip. The
> > patch is big, if you need it splitted into small patches I can do it.
>
> Your patch didn't apply:
>
> patching file drivers/media/video/zr364xx.c
> Hunk #4 FAILED at 37.
> Hunk #5 succeeded at 114 (offset 2 lines).
> Hunk #7 succeeded at 474 (offset 2 lines).
> Hunk #9 succeeded at 782 (offset 2 lines).
> Hunk #11 succeeded at 848 (offset 2 lines).
> Hunk #13 succeeded at 918 (offset 2 lines).
> Hunk #15 succeeded at 1198 (offset 2 lines).
> Hunk #17 succeeded at 1242 (offset 2 lines).
> Hunk #19 succeeded at 1373 (offset 2 lines).
> Hunk #21 succeeded at 1409 (offset 2 lines).
> Hunk #23 succeeded at 1532 (offset 2 lines).
> 1 out of 24 hunks FAILED -- saving rejects to file
> drivers/media/video/zr364xx.c.rej Patch doesn't apply
>
> Probably because you didn't generate it against the development tree. Could
> you please re-generate it against: http://linuxtv.org/hg/v4l-dvbg/v4l-dvb
>
> The better is to clone it using:
> hg clone http://linuxtv.org/hg/v4l-dvb
>
>
> Also, please test it against checkpatch tool, since there are a few coding
> style issues like:
>
> }
> else {
>
> and
> if (foo)
> {
>
> Violating Linux codingstyle. For more info, please read the README.patches
> file at the tree.
>
> > Lamarque V. Souza
> > http://www.geographicguide.com/brazil.htm
> > Linux User #57137 - http://counter.li.org/
>
> Legal! outro brasileiro na lista! Bem vindo ao time.
Hehe, obrigado.
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
[-- Attachment #2: zr364xx.c-streaming.patch-v4l-dvb-20090327 --]
[-- Type: text/x-patch, Size: 40511 bytes --]
--- v4l-dvb/linux/drivers/media/video/zr364xx.c 2009-03-27 15:18:54.050413997 -0300
+++ v4l-dvb/linux-lvs/drivers/media/video/zr364xx.c 2009-03-27 15:22:47.914414277 -0300
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,7 +27,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -36,25 +37,34 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
#include "compat.h"
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
+#define FRAMES 1
#define MAX_FRAME_SIZE 100000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
@@ -103,24 +113,97 @@ static struct usb_device_id device_table
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
+ ZR364XX_READ_FRAME */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 transfer_flags;;
+ u32 state;
+ u32 prev_state;
+ u32 urb_size;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+ u32 priority_set;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt *fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -274,139 +357,120 @@ static unsigned char header2[] = {
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
-/********************/
-/* V4L2 integration */
-/********************/
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
-
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
-
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
-
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
-
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf)
+{
+ DBG("%s\n", __func__);
+
+ /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
+ * after running Skype on an AMD64 system. */
+ /*videobuf_waiton(&buf->vb, 0, 0);*/
+
+ if (in_interrupt())
+ BUG();
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+ cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
}
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
}
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ DBG("%s\n", __func__);
- return size;
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
}
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+ DBG("%s\n", __func__);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
+
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_read: read %d bytes.", (int) count);
+ struct zr364xx_camera *cam = video_drvdata(file);
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -414,22 +478,273 @@ static ssize_t zr364xx_read(struct file
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+ (int) *ppos);
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+ return 0;
+}
- return count;
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+ struct zr364xx_buffer *buf,
+ int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
}
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ /*DBG("buffer to user\n");*/
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16 *)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ if (frm->lpvbits == NULL) {
+ DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
+ frm, cam, idx);
+ return -ENOMEM;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
+
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ } else if (cam->b_acquire) {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
+
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
+}
+
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
+}
+
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct zr364xx_camera *cam = video_drvdata(file);
+
memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ sizeof(cap->bus_info));
+ cap->version = ZR364_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
return 0;
}
@@ -463,12 +778,11 @@ static int zr364xx_vidioc_s_input(struct
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -477,7 +791,7 @@ static int zr364xx_vidioc_queryctrl(stru
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -489,36 +803,42 @@ static int zr364xx_vidioc_queryctrl(stru
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -537,28 +857,44 @@ static int zr364xx_vidioc_enum_fmt_vid_c
f->index = 0;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
+ }
+
+ /* Lamarque 25/03/2009: Skype + libv4l do not work if we return
+ * -EINVAL here. */
+ /*if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE) {
+ DBG("%s: unsupported field value %d\n",__func__,
+ f->fmt.pix.field);
return -EINVAL;
+ }*/
+
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -566,24 +902,26 @@ static int zr364xx_vidioc_try_fmt_vid_ca
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
return 0;
}
static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -594,23 +932,26 @@ static int zr364xx_vidioc_g_fmt_vid_cap(
return 0;
}
+/* Lamarque TODO: implement changing resolution on the fly */
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -618,19 +959,260 @@ static int zr364xx_vidioc_s_fmt_vid_cap(
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
- DBG("ok!");
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int pipe;
+
+ pipe_info = purb->context;
+ /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+ if (purb->status != 0) {
+ DBG("_%s: err status = %d\n", __func__, purb->status);
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 ||
+ purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+
+ pipe_info->err_count = 0;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ dev_err(&cam->udev->dev, "error submitting urb\n");
+ usb_free_urb(pipe_info->stream_urb);
+ }
+ } else {
+ DBG("read pipe complete state 0\n");
+ }
+ return;
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->priority_set = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ pipe_info->urb_size = sizeof(pipe_info->stream_urb);
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0) {
+ pipe_info->state = 0;
+ pipe_info->prev_state = 1;
+ }
+
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ DBG("stop read pipe\n");
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ cam->b_acquire = 1;
+ } else {
+ res_free(cam);
+ }
+ DBG("%s: %d\n", __func__, res);
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -639,28 +1221,19 @@ static int zr364xx_vidioc_streamoff(stru
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -676,6 +1249,14 @@ static int zr364xx_open(struct file *fil
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -684,28 +1265,70 @@ static int zr364xx_open(struct file *fil
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+
+ DBG("%s\n", __func__);
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -728,40 +1351,43 @@ static int zr364xx_release(struct file *
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_mmap: %ld\n", size);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- if (vdev == NULL)
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
- cam = video_get_drvdata(vdev);
-
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
}
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- return 0;
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -770,6 +1396,7 @@ static const struct v4l2_file_operations
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -786,6 +1413,10 @@ static const struct v4l2_ioctl_ops zr364
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -801,15 +1432,75 @@ static struct video_device zr364xx_templ
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+ "Using less frames\n");
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ return -ENOMEM;
+ } else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -831,19 +1522,13 @@ static int zr364xx_probe(struct usb_inte
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -870,21 +1555,48 @@ static int zr364xx_probe(struct usb_inte
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ zr364xx_board_init(cam);
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -894,15 +1606,13 @@ static int zr364xx_probe(struct usb_inte
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
if (cam->vdev)
video_unregister_device(cam->vdev);
cam->vdev = NULL;
- kfree(cam->buffer);
- if (cam->framebuf)
- vfree(cam->framebuf);
- kfree(cam);
+ zr364xx_destroy(cam);
}
Signed-off-by: Lamarque V. Souza (lamarque@gmail.com)
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: Patch implementing V4L2_CAP_STREAMING for zr364xx driver
2009-03-27 18:39 ` Lamarque Vieira Souza
@ 2009-03-28 9:34 ` Mauro Carvalho Chehab
2009-03-28 10:11 ` [PATCH] Implement " Lamarque Vieira Souza
0 siblings, 1 reply; 21+ messages in thread
From: Mauro Carvalho Chehab @ 2009-03-28 9:34 UTC (permalink / raw)
To: Lamarque Vieira Souza; +Cc: Antoine Jacquet, linux-media, video4linux-list
Lamarque,
On Fri, 27 Mar 2009 15:39:26 -0300
Lamarque Vieira Souza <lamarque@gmail.com> wrote:
> Here is the patch with the modifications you asked.
There's just one important part missing on your patch: you forgot so send your
Signed-off-by: (please read README.patches file, at v4l-dvb tree:
http://linuxtv.org/hg/v4l-dvb/raw-file/tip/README.patches).
Also, you didn't provide a description.
So, I need you to re-send at the proper format, by adding a subject line like:
[PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
And the body of the email should contain just the description plus your patch. Something like:
This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
converting the driver to use videobuf.
Tested with PC-CAM 880.
It basically:
. re-implements V4L2_CAP_READWRITE using videobuf;
. copies cam->udev->product to the card field of the v4l2_capability struct.
That gives more information to the users about the webcam;
. moves the brightness setting code from before requesting a frame (in
read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
executed only when the application request a change in brightness and
not before every frame read;
. comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype + libv4l
do not work.
This patch fixes zr364xx for applications such as mplayer,
Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
with zr364xx chip.
Signed-off-by: <your name/email should be here>
<the patch>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-03-28 9:34 ` Mauro Carvalho Chehab
@ 2009-03-28 10:11 ` Lamarque Vieira Souza
2009-03-28 11:44 ` Hans de Goede
2009-07-03 2:09 ` Lamarque Vieira Souza
0 siblings, 2 replies; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-03-28 10:11 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Antoine Jacquet, linux-media, video4linux-list
This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
converting the driver to use videobuf.
Tested with Creative PC-CAM 880.
It basically:
. implements V4L2_CAP_STREAMING using videobuf;
. re-implements V4L2_CAP_READWRITE using videobuf;
. copies cam->udev->product to the card field of the v4l2_capability struct.
That gives more information to the users about the webcam;
. moves the brightness setting code from before requesting a frame (in
read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
executed only when the application requests a change in brightness and
not before every frame read;
. comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
libv4l do not work.
This patch fixes zr364xx for applications such as mplayer,
Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
with zr364xx chip.
Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
---
--- v4l-dvb/linux/drivers/media/video/zr364xx.c 2009-03-27 15:18:54.050413997
-0300
+++ v4l-dvb/linux-lvs/drivers/media/video/zr364xx.c 2009-03-27
15:22:47.914414277 -0300
@@ -1,5 +1,5 @@
/*
- * Zoran 364xx based USB webcam module version 0.72
+ * Zoran 364xx based USB webcam module version 0.73
*
* Allows you to use your USB webcam with V4L2 applications
* This is still in heavy developpement !
@@ -10,6 +10,8 @@
* Heavily inspired by usb-skeleton.c, vicam.c, cpia.c and spca50x.c drivers
* V4L2 version inspired by meye.c driver
*
+ * Some video buffer code by Lamarque based on s2255drv.c and vivi.c drivers.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,7 +27,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -36,25 +37,34 @@
#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/videobuf-vmalloc.h>
#include "compat.h"
/* Version Information */
-#define DRIVER_VERSION "v0.72"
+#define DRIVER_VERSION "v0.73"
+#define ZR364_VERSION_CODE KERNEL_VERSION(0, 7, 3)
#define DRIVER_AUTHOR "Antoine Jacquet, http://royale.zerezo.com/"
#define DRIVER_DESC "Zoran 364xx"
/* Camera */
-#define FRAMES 2
+#define FRAMES 1
#define MAX_FRAME_SIZE 100000
#define BUFFER_SIZE 0x1000
#define CTRL_TIMEOUT 500
+#define ZR364XX_DEF_BUFS 4
+#define ZR364XX_READ_IDLE 0
+#define ZR364XX_READ_FRAME 1
/* Debug macro */
-#define DBG(x...) if (debug) printk(KERN_INFO KBUILD_MODNAME x)
-
+#define DBG(fmt, args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_INFO KBUILD_MODNAME " " fmt, ##args); \
+ } \
+ } while (0)
/* Init methods, need to find nicer names for these
* the exact names of the chipsets would be the best if someone finds it */
@@ -103,24 +113,97 @@ static struct usb_device_id device_table
MODULE_DEVICE_TABLE(usb, device_table);
+struct zr364xx_mode {
+ u32 color; /* output video color format */
+ u32 brightness; /* brightness */
+};
+
+/* frame structure */
+struct zr364xx_framei {
+ unsigned long ulState; /* ulState:ZR364XX_READ_IDLE,
+ ZR364XX_READ_FRAME */
+ void *lpvbits; /* image data */
+ unsigned long cur_size; /* current data copied to it */
+};
+
+/* image buffer structure */
+struct zr364xx_bufferi {
+ unsigned long dwFrames; /* number of frames in buffer */
+ struct zr364xx_framei frame[FRAMES]; /* array of FRAME structures */
+};
+
+struct zr364xx_dmaqueue {
+ struct list_head active;
+ struct zr364xx_camera *cam;
+};
+
+struct zr364xx_pipeinfo {
+ u32 transfer_size;
+ u8 *transfer_buffer;
+ u32 transfer_flags;;
+ u32 state;
+ u32 prev_state;
+ u32 urb_size;
+ void *stream_urb;
+ void *cam; /* back pointer to zr364xx_camera struct */
+ u32 err_count;
+ u32 idx;
+ u32 priority_set;
+};
+
+struct zr364xx_fmt {
+ char *name;
+ u32 fourcc;
+ int depth;
+};
+
+/* image formats. */
+static const struct zr364xx_fmt formats[] = {
+ {
+ .name = "JPG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .depth = 24
+ }
+};
/* Camera stuff */
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
struct video_device *vdev; /* v4l video device */
- u8 *framebuf;
int nb;
- unsigned char *buffer;
+ struct zr364xx_bufferi buffer;
int skip;
- int brightness;
int width;
int height;
int method;
struct mutex lock;
+ struct mutex open_lock;
int users;
+
+ spinlock_t slock;
+ struct zr364xx_dmaqueue vidq;
+ int resources;
+ int last_frame;
+ int cur_frame;
+ unsigned long frame_count;
+ int b_acquire;
+ struct zr364xx_pipeinfo pipe[1];
+
+ u8 read_endpoint;
+
+ const struct zr364xx_fmt *fmt;
+ struct videobuf_queue vb_vidq;
+ enum v4l2_buf_type type;
+ struct zr364xx_mode mode;
};
+/* buffer for one video frame */
+struct zr364xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ const struct zr364xx_fmt *fmt;
+};
/* function used to send initialisation commands to the camera */
static int send_control_msg(struct usb_device *udev, u8 request, u16 value,
@@ -274,139 +357,120 @@ static unsigned char header2[] = {
};
static unsigned char header3;
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
-/********************/
-/* V4L2 integration */
-/********************/
+ *size = cam->width * cam->height * (cam->fmt->depth >> 3);
-/* this function reads a full JPEG picture synchronously
- * TODO: do it asynchronously... */
-static int read_frame(struct zr364xx_camera *cam, int framenum)
-{
- int i, n, temp, head, size, actual_length;
- unsigned char *ptr = NULL, *jpeg;
-
- redo:
- /* hardware brightness */
- n = send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
- temp = (0x60 << 8) + 127 - cam->brightness;
- n = send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
-
- /* during the first loop we are going to insert JPEG header */
- head = 0;
- /* this is the place in memory where we are going to build
- * the JPEG image */
- jpeg = cam->framebuf + framenum * MAX_FRAME_SIZE;
- /* read data... */
- do {
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, 0x81),
- cam->buffer, BUFFER_SIZE, &actual_length,
- CTRL_TIMEOUT);
- DBG("buffer : %d %d", cam->buffer[0], cam->buffer[1]);
- DBG("bulk : n=%d size=%d", n, actual_length);
- if (n < 0) {
- dev_err(&cam->udev->dev, "error reading bulk msg\n");
- return 0;
- }
- if (actual_length < 0 || actual_length > BUFFER_SIZE) {
- dev_err(&cam->udev->dev, "wrong number of bytes\n");
- return 0;
- }
-
- /* swap bytes if camera needs it */
- if (cam->method == METHOD0) {
- u16 *buf = (u16*)cam->buffer;
- for (i = 0; i < BUFFER_SIZE/2; i++)
- swab16s(buf + i);
- }
-
- /* write the JPEG header */
- if (!head) {
- DBG("jpeg header");
- ptr = jpeg;
- memcpy(ptr, header1, sizeof(header1));
- ptr += sizeof(header1);
- header3 = 0;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer, 64);
- ptr += 64;
- header3 = 1;
- memcpy(ptr, &header3, 1);
- ptr++;
- memcpy(ptr, cam->buffer + 64, 64);
- ptr += 64;
- memcpy(ptr, header2, sizeof(header2));
- ptr += sizeof(header2);
- memcpy(ptr, cam->buffer + 128,
- actual_length - 128);
- ptr += actual_length - 128;
- head = 1;
- DBG("header : %d %d %d %d %d %d %d %d %d",
- cam->buffer[0], cam->buffer[1], cam->buffer[2],
- cam->buffer[3], cam->buffer[4], cam->buffer[5],
- cam->buffer[6], cam->buffer[7], cam->buffer[8]);
- } else {
- memcpy(ptr, cam->buffer, actual_length);
- ptr += actual_length;
- }
- }
- /* ... until there is no more */
- while (actual_length == BUFFER_SIZE);
-
- /* we skip the 2 first frames which are usually buggy */
- if (cam->skip) {
- cam->skip--;
- goto redo;
- }
-
- /* go back to find the JPEG EOI marker */
- size = ptr - jpeg;
- ptr -= 2;
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xD9
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
- }
- if (ptr == jpeg)
- DBG("No EOI marker");
+ if (*count == 0)
+ *count = ZR364XX_DEF_BUFS;
- /* Sometimes there is junk data in the middle of the picture,
- * we want to skip this bogus frames */
- while (ptr > jpeg) {
- if (*ptr == 0xFF && *(ptr + 1) == 0xFF
- && *(ptr + 2) == 0xFF)
- break;
- ptr--;
+ while (*size * (*count) > ZR364XX_DEF_BUFS * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer
*buf)
+{
+ DBG("%s\n", __func__);
+
+ /*Lamarque: is this really needed? Sometimes this blocks rmmod forever
+ * after running Skype on an AMD64 system. */
+ /*videobuf_waiton(&buf->vb, 0, 0);*/
+
+ if (in_interrupt())
+ BUG();
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer
*vb,
+ enum v4l2_field field)
+{
+ struct zr364xx_camera *cam = vq->priv_data;
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ int rc;
+
+ DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ?
+ cam->fmt->name : "");
+ if (cam->fmt == NULL)
+ return -EINVAL;
+
+ buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3);
+
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size) {
+ DBG("invalid buffer prepare\n");
+ return -EINVAL;
}
- if (ptr != jpeg) {
- DBG("Bogus frame ? %d", cam->nb);
- goto redo;
+
+ buf->fmt = cam->fmt;
+ buf->vb.width = cam->width;
+ buf->vb.height = cam->height;
+ buf->vb.field = field;
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
}
- DBG("jpeg : %d %d %d %d %d %d %d %d",
- jpeg[0], jpeg[1], jpeg[2], jpeg[3],
- jpeg[4], jpeg[5], jpeg[6], jpeg[7]);
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer
*vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
+ struct zr364xx_camera *cam = vq->priv_data;
+
+ DBG("%s\n", __func__);
- return size;
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &cam->vidq.active);
}
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer,
+ vb);
-static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
+ DBG("%s\n", __func__);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops zr364xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************/
+/* V4L2 integration */
+/********************/
+static int zr364xx_vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type);
+
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t
count,
loff_t * ppos)
{
- unsigned long count = cnt;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_read: read %d bytes.", (int) count);
+ struct zr364xx_camera *cam = video_drvdata(file);
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ DBG("%s\n", __func__);
if (!buf)
return -EINVAL;
@@ -414,22 +478,273 @@ static ssize_t zr364xx_read(struct file
if (!count)
return -EINVAL;
- /* NoMan Sux ! */
- count = read_frame(cam, 0);
+ if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
+ DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
+ (int) *ppos);
+ return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ }
- if (copy_to_user(buf, cam->framebuf, count))
- return -EFAULT;
+ return 0;
+}
- return count;
+/* video buffer vmalloc implementation based partly on VIVI driver which is
+ * Copyright (c) 2006 by
+ * Mauro Carvalho Chehab <mchehab--a.t--infradead.org>
+ * Ted Walther <ted--a.t--enumera.com>
+ * John Sokol <sokol--a.t--videotechnology.com>
+ * http://v4l.videotechnology.com/
+ *
+ */
+static void zr364xx_fillbuff(struct zr364xx_camera *cam,
+ struct zr364xx_buffer *buf,
+ int jpgsize)
+{
+ int pos = 0;
+ struct timeval ts;
+ const char *tmpbuf;
+ char *vbuf = videobuf_to_vmalloc(&buf->vb);
+ unsigned long last_frame;
+ struct zr364xx_framei *frm;
+
+ if (!vbuf)
+ return;
+
+ last_frame = cam->last_frame;
+ if (last_frame != -1) {
+ frm = &cam->buffer.frame[last_frame];
+ tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
+ switch (buf->fmt->fourcc) {
+ case V4L2_PIX_FMT_JPEG:
+ buf->vb.size = jpgsize;
+ memcpy(vbuf, tmpbuf, buf->vb.size);
+ break;
+ default:
+ printk(KERN_DEBUG KBUILD_MODNAME ": unknown format?\n");
+ }
+ cam->last_frame = -1;
+ } else {
+ printk(KERN_ERR KBUILD_MODNAME ": =======no frame\n");
+ return;
+ }
+ DBG("%s: Buffer 0x%08lx size= %d\n", __func__,
+ (unsigned long)vbuf, pos);
+ /* tell v4l buffer was filled */
+
+ buf->vb.field_count = cam->frame_count * 2;
+ do_gettimeofday(&ts);
+ buf->vb.ts = ts;
+ buf->vb.state = VIDEOBUF_DONE;
+}
+
+static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
+{
+ struct zr364xx_dmaqueue *dma_q = &cam->vidq;
+ struct zr364xx_buffer *buf;
+ unsigned long flags = 0;
+ int rc = 0;
+
+ DBG("wakeup: %p\n", &dma_q);
+ spin_lock_irqsave(&cam->slock, flags);
+
+ if (list_empty(&dma_q->active)) {
+ DBG("No active queue to serve\n");
+ rc = -1;
+ goto unlock;
+ }
+ buf = list_entry(dma_q->active.next,
+ struct zr364xx_buffer, vb.queue);
+
+ if (!waitqueue_active(&buf->vb.done)) {
+ /* no one active */
+ rc = -1;
+ goto unlock;
+ }
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ DBG("[%p/%d] wakeup\n", buf, buf->vb.i);
+ zr364xx_fillbuff(cam, buf, jpgsize);
+ wake_up(&buf->vb.done);
+ DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
+unlock:
+ spin_unlock_irqrestore(&cam->slock, flags);
+ return 0;
}
+/* this function moves the usb stream read pipe data
+ * into the system buffers.
+ * returns 0 on success, EAGAIN if more data to process (call this
+ * function again).
+ */
+static int zr364xx_read_video_callback(struct zr364xx_camera *cam,
+ struct zr364xx_pipeinfo *pipe_info,
+ struct urb *purb)
+{
+ unsigned char *pdest;
+ unsigned char *psrc;
+ s32 idx = -1;
+ struct zr364xx_framei *frm;
+ int i = 0;
+ unsigned char *ptr = NULL;
+
+ /*DBG("buffer to user\n");*/
+ idx = cam->cur_frame;
+ frm = &cam->buffer.frame[idx];
+
+ /* swap bytes if camera needs it */
+ if (cam->method == METHOD0) {
+ u16 *buf = (u16 *)pipe_info->transfer_buffer;
+ for (i = 0; i < purb->actual_length/2; i++)
+ swab16s(buf + i);
+ }
+
+ /* search done. now find out if should be acquiring */
+ if (!cam->b_acquire) {
+ /* we found a frame, but this channel is turned off */
+ frm->ulState = ZR364XX_READ_IDLE;
+ return -EINVAL;
+ }
+
+ if (frm->lpvbits == NULL) {
+ DBG("%s: frame buffer == NULL.%p %p %d\n", __func__,
+ frm, cam, idx);
+ return -ENOMEM;
+ }
+
+ psrc = (u8 *)pipe_info->transfer_buffer;
+ ptr = pdest = frm->lpvbits;
+
+ if (frm->ulState == ZR364XX_READ_IDLE) {
+ frm->ulState = ZR364XX_READ_FRAME;
+ frm->cur_size = 0;
+
+ DBG("jpeg header, ");
+ memcpy(ptr, header1, sizeof(header1));
+ ptr += sizeof(header1);
+ header3 = 0;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc, 64);
+ ptr += 64;
+ header3 = 1;
+ memcpy(ptr, &header3, 1);
+ ptr++;
+ memcpy(ptr, psrc + 64, 64);
+ ptr += 64;
+ memcpy(ptr, header2, sizeof(header2));
+ ptr += sizeof(header2);
+ memcpy(ptr, psrc + 128,
+ purb->actual_length - 128);
+ ptr += purb->actual_length - 128;
+ DBG("header : %d %d %d %d %d %d %d %d %d\n",
+ psrc[0], psrc[1], psrc[2],
+ psrc[3], psrc[4], psrc[5],
+ psrc[6], psrc[7], psrc[8]);
+ frm->cur_size = ptr - pdest;
+ } else {
+ pdest += frm->cur_size;
+ memcpy(pdest, psrc, purb->actual_length);
+ frm->cur_size += purb->actual_length;
+ }
+ /*DBG("cur_size %lu urb size %d\n", frm->cur_size,
+ purb->actual_length);*/
+
+ if (purb->actual_length < pipe_info->transfer_size) {
+ DBG("****************Buffer[%d]full*************\n", idx);
+ cam->last_frame = cam->cur_frame;
+ cam->cur_frame++;
+ /* end of system frame ring buffer, start at zero */
+ if (cam->cur_frame == cam->buffer.dwFrames)
+ cam->cur_frame = 0;
+
+ /* frame ready */
+ /* go back to find the JPEG EOI marker */
+ ptr = pdest = frm->lpvbits;
+ ptr += frm->cur_size - 2;
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xD9
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr == pdest)
+ DBG("No EOI marker\n");
+
+ /* Sometimes there is junk data in the middle of the picture,
+ * we want to skip this bogus frames */
+ while (ptr > pdest) {
+ if (*ptr == 0xFF && *(ptr + 1) == 0xFF
+ && *(ptr + 2) == 0xFF)
+ break;
+ ptr--;
+ }
+ if (ptr != pdest) {
+ DBG("Bogus frame ? %d\n", ++(cam->nb));
+ } else if (cam->b_acquire) {
+ /* we skip the 2 first frames which are usually buggy */
+ if (cam->skip)
+ cam->skip--;
+ else {
+ DBG("jpeg(%lu): %d %d %d %d %d %d %d %d\n",
+ frm->cur_size,
+ pdest[0], pdest[1], pdest[2], pdest[3],
+ pdest[4], pdest[5], pdest[6], pdest[7]);
+
+ zr364xx_got_frame(cam, frm->cur_size);
+ }
+ }
+ cam->frame_count++;
+ frm->ulState = ZR364XX_READ_IDLE;
+ frm->cur_size = 0;
+ }
+ /* done successfully */
+ return 0;
+}
+
+static int res_get(struct zr364xx_camera *cam)
+{
+ /* is it free? */
+ mutex_lock(&cam->lock);
+ if (cam->resources) {
+ /* no, someone else uses it */
+ mutex_unlock(&cam->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ cam->resources = 1;
+ DBG("res: get\n");
+ mutex_unlock(&cam->lock);
+ return 1;
+}
+
+static inline int res_check(struct zr364xx_camera *cam)
+{
+ return cam->resources;
+}
+
+static void res_free(struct zr364xx_camera *cam)
+{
+ mutex_lock(&cam->lock);
+ cam->resources = 0;
+ mutex_unlock(&cam->lock);
+ DBG("res: put\n");
+}
static int zr364xx_vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
+ struct zr364xx_camera *cam = video_drvdata(file);
+
memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, DRIVER_DESC);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ strlcpy(cap->driver, DRIVER_DESC, sizeof(cap->driver));
+ strlcpy(cap->card, cam->udev->product, sizeof(cap->card));
+ strlcpy(cap->bus_info, dev_name(&cam->udev->dev),
+ sizeof(cap->bus_info));
+ cap->version = ZR364_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
return 0;
}
@@ -463,12 +778,11 @@ static int zr364xx_vidioc_s_input(struct
static int zr364xx_vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
@@ -477,7 +791,7 @@ static int zr364xx_vidioc_queryctrl(stru
c->minimum = 0;
c->maximum = 127;
c->step = 1;
- c->default_value = cam->brightness;
+ c->default_value = cam->mode.brightness;
c->flags = 0;
break;
default:
@@ -489,36 +803,42 @@ static int zr364xx_vidioc_queryctrl(stru
static int zr364xx_vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
+ int temp;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = c->value;
+ cam->mode.brightness = c->value;
+ /* hardware brightness */
+ mutex_lock(&cam->lock);
+ send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
+ temp = (0x60 << 8) + 127 - cam->mode.brightness;
+ send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
+ mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
}
+
return 0;
}
static int zr364xx_vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *c)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- c->value = cam->brightness;
+ c->value = cam->mode.brightness;
break;
default:
return -EINVAL;
@@ -537,28 +857,44 @@ static int zr364xx_vidioc_enum_fmt_vid_c
f->index = 0;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "JPEG");
- f->pixelformat = V4L2_PIX_FMT_JPEG;
+ strcpy(f->description, formats[0].name);
+ f->pixelformat = formats[0].fourcc;
return 0;
}
+static char *decode_fourcc(__u32 pixelformat, char *buf)
+{
+ buf[0] = pixelformat & 0xff;
+ buf[1] = (pixelformat >> 8) & 0xff;
+ buf[2] = (pixelformat >> 16) & 0xff;
+ buf[3] = (pixelformat >> 24) & 0xff;
+ buf[4] = '\0';
+ return buf;
+}
+
static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ char pixelformat_name[5];
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) {
+ DBG("%s: unsupported pixelformat V4L2_PIX_FMT_%s\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name));
return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
+ }
+
+ /* Lamarque 25/03/2009: Skype + libv4l do not work if we return
+ * -EINVAL here. */
+ /*if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE) {
+ DBG("%s: unsupported field value %d\n",__func__,
+ f->fmt.pix.field);
return -EINVAL;
+ }*/
+
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -566,24 +902,26 @@ static int zr364xx_vidioc_try_fmt_vid_ca
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
return 0;
}
static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
- if (vdev == NULL)
+ if (file == NULL)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ cam = video_drvdata(file);
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
+ f->fmt.pix.pixelformat = formats[0].fourcc;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -594,23 +932,26 @@ static int zr364xx_vidioc_g_fmt_vid_cap(
return 0;
}
+/* Lamarque TODO: implement changing resolution on the fly */
static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- if (vdev == NULL)
- return -ENODEV;
- cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ char pixelformat_name[5];
+ int ret = zr364xx_vidioc_try_fmt_vid_cap(file, cam, f);
+
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&cam->vb_vidq)) {
+ DBG("%s queue busy\n", __func__);
+ ret = -EBUSY;
+ goto out;
+ }
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = cam->width;
f->fmt.pix.height = cam->height;
@@ -618,19 +959,260 @@ static int zr364xx_vidioc_s_fmt_vid_cap(
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
- DBG("ok!");
+ cam->vb_vidq.field = f->fmt.pix.field;
+ cam->mode.color = V4L2_PIX_FMT_JPEG;
+ ret = 0;
+
+out:
+ mutex_unlock(&q->vb_lock);
+
+ DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__,
+ decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name),
+ f->fmt.pix.field);
+ return ret;
+}
+
+static int zr364xx_vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_reqbufs(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_querybuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ rc = videobuf_querybuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_qbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_qbuf(&cam->vb_vidq, p);
+ return rc;
+}
+
+static int zr364xx_vidioc_dqbuf(struct file *file,
+ void *priv,
+ struct v4l2_buffer *p)
+{
+ int rc;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ DBG("%s\n", __func__);
+ rc = videobuf_dqbuf(&cam->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return rc;
+}
+
+static void read_pipe_completion(struct urb *purb)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+ struct zr364xx_camera *cam;
+ int pipe;
+
+ pipe_info = purb->context;
+ /*DBG("%s %p, status %d\n", __func__, purb, purb->status);*/
+ if (pipe_info == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+
+ cam = pipe_info->cam;
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": no context!\n");
+ return;
+ }
+ if (purb->status != 0) {
+ DBG("_%s: err status = %d\n", __func__, purb->status);
+ return;
+ }
+
+ if (pipe_info->state == 0) {
+ DBG("exiting USB pipe\n");
+ return;
+ }
+
+ if (purb->actual_length < 0 ||
+ purb->actual_length > pipe_info->transfer_size) {
+ dev_err(&cam->udev->dev, "wrong number of bytes\n");
+ return;
+ }
+
+ zr364xx_read_video_callback(cam, pipe_info, purb);
+
+ pipe_info->err_count = 0;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+
+ /* reuse urb */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ dev_err(&cam->udev->dev, "error submitting urb\n");
+ usb_free_urb(pipe_info->stream_urb);
+ }
+ } else {
+ DBG("read pipe complete state 0\n");
+ }
+ return;
+}
+
+static int zr364xx_start_readpipe(struct zr364xx_camera *cam)
+{
+ int pipe;
+ int retval;
+ struct zr364xx_pipeinfo *pipe_info = cam->pipe;
+ pipe = usb_rcvbulkpipe(cam->udev, cam->read_endpoint);
+ DBG("%s: start pipe IN x%x\n", __func__, cam->read_endpoint);
+
+ pipe_info->state = 1;
+ pipe_info->priority_set = 0;
+ pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!pipe_info->stream_urb) {
+ dev_err(&cam->udev->dev, "ReadStream: Unable to alloc URB\n");
+ return -ENOMEM;
+ }
+ /* transfer buffer allocated in board_init */
+ usb_fill_bulk_urb(pipe_info->stream_urb, cam->udev,
+ pipe,
+ pipe_info->transfer_buffer,
+ pipe_info->transfer_size,
+ read_pipe_completion, pipe_info);
+
+ pipe_info->urb_size = sizeof(pipe_info->stream_urb);
+ DBG("submitting URB %p\n", pipe_info->stream_urb);
+ retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
+ if (retval) {
+ printk(KERN_ERR KBUILD_MODNAME ": start read pipe failed\n");
+ return retval;
+ }
+
+ return 0;
+}
+
+static void zr364xx_stop_readpipe(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe_info;
+
+ if (cam == NULL) {
+ printk(KERN_ERR KBUILD_MODNAME ": invalid device\n");
+ return;
+ }
+ DBG("stop read pipe\n");
+ pipe_info = cam->pipe;
+ if (pipe_info) {
+ if (pipe_info->state != 0) {
+ pipe_info->state = 0;
+ pipe_info->prev_state = 1;
+ }
+
+ if (pipe_info->stream_urb) {
+ /* cancel urb */
+ usb_kill_urb(pipe_info->stream_urb);
+ usb_free_urb(pipe_info->stream_urb);
+ pipe_info->stream_urb = NULL;
+ }
+ }
+ DBG("stop read pipe\n");
+ return;
+}
+
+/* starts acquisition process */
+static int zr364xx_start_acquire(struct zr364xx_camera *cam)
+{
+ int j;
+
+ DBG("start acquire\n");
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ return 0;
+}
+
+static inline int zr364xx_stop_acquire(struct zr364xx_camera *cam)
+{
+ cam->b_acquire = 0;
return 0;
}
static int zr364xx_vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- return 0;
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int j;
+ int res;
+
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+
+ if (!res_get(cam)) {
+ dev_err(&cam->udev->dev, "stream busy\n");
+ return -EBUSY;
+ }
+
+ cam->last_frame = -1;
+ cam->cur_frame = 0;
+ cam->frame_count = 0;
+ for (j = 0; j < FRAMES; j++) {
+ cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[j].cur_size = 0;
+ }
+ res = videobuf_streamon(&cam->vb_vidq);
+ if (res == 0) {
+ zr364xx_start_acquire(cam);
+ cam->b_acquire = 1;
+ } else {
+ res_free(cam);
+ }
+ DBG("%s: %d\n", __func__, res);
+ return res;
}
static int zr364xx_vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
+ int res;
+ struct zr364xx_camera *cam = video_drvdata(file);
+
+ DBG("%s\n", __func__);
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&cam->udev->dev, "invalid fh type0\n");
+ return -EINVAL;
+ }
+ if (cam->type != type) {
+ dev_err(&cam->udev->dev, "invalid fh type1\n");
+ return -EINVAL;
+ }
+ zr364xx_stop_acquire(cam);
+ res = videobuf_streamoff(&cam->vb_vidq);
+ if (res < 0)
+ return res;
+ res_free(cam);
return 0;
}
@@ -639,28 +1221,19 @@ static int zr364xx_vidioc_streamoff(stru
static int zr364xx_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam = video_get_drvdata(vdev);
+ struct zr364xx_camera *cam = video_drvdata(file);
struct usb_device *udev = cam->udev;
int i, err;
- DBG("zr364xx_open");
+ DBG("%s\n", __func__);
- mutex_lock(&cam->lock);
+ mutex_lock(&cam->open_lock);
if (cam->users) {
err = -EBUSY;
goto out;
}
- if (!cam->framebuf) {
- cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES);
- if (!cam->framebuf) {
- dev_err(&cam->udev->dev, "vmalloc_32 failed!\n");
- err = -ENOMEM;
- goto out;
- }
- }
-
for (i = 0; init[cam->method][i].size != -1; i++) {
err =
send_control_msg(udev, 1, init[cam->method][i].value,
@@ -676,6 +1249,14 @@ static int zr364xx_open(struct file *fil
cam->skip = 2;
cam->users++;
file->private_data = vdev;
+ cam->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ cam->fmt = formats;
+
+ videobuf_queue_vmalloc_init(&cam->vb_vidq, &zr364xx_video_qops,
+ NULL, &cam->slock,
+ cam->type,
+ V4L2_FIELD_NONE,
+ sizeof(struct zr364xx_buffer), cam);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
@@ -684,28 +1265,70 @@ static int zr364xx_open(struct file *fil
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+ DBG("%s: %d\n", __func__, err);
return err;
}
+static void zr364xx_destroy(struct zr364xx_camera *cam)
+{
+ unsigned long i;
+
+ if (!cam) {
+ printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
+ return;
+ }
+ mutex_lock(&cam->open_lock);
+ if (cam->vdev)
+ video_unregister_device(cam->vdev);
+ cam->vdev = NULL;
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+
+ /* release sys buffers */
+ for (i = 0; i < FRAMES; i++) {
+ if (cam->buffer.frame[i].lpvbits) {
+ DBG("vfree %p\n", cam->buffer.frame[i].lpvbits);
+ vfree(cam->buffer.frame[i].lpvbits);
+ }
+ cam->buffer.frame[i].lpvbits = NULL;
+ }
+
+ /* release transfer buffer */
+ kfree(cam->pipe->transfer_buffer);
+
+ DBG("%s\n", __func__);
+ mutex_unlock(&cam->open_lock);
+ kfree(cam);
+}
/* release the camera */
static int zr364xx_release(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct zr364xx_camera *cam;
struct usb_device *udev;
int i, err;
- DBG("zr364xx_release");
+ DBG("%s\n", __func__);
+ cam = video_drvdata(file);
- if (vdev == NULL)
+ if (!cam)
return -ENODEV;
- cam = video_get_drvdata(vdev);
+ mutex_lock(&cam->open_lock);
udev = cam->udev;
- mutex_lock(&cam->lock);
+ /* turn off stream */
+ if (res_check(cam)) {
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+ videobuf_streamoff(&cam->vb_vidq);
+ res_free(cam);
+ }
cam->users--;
file->private_data = NULL;
@@ -728,40 +1351,43 @@ static int zr364xx_release(struct file *
err = 0;
out:
- mutex_unlock(&cam->lock);
+ mutex_unlock(&cam->open_lock);
+
return err;
}
static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma)
{
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct video_device *vdev = video_devdata(file);
- struct zr364xx_camera *cam;
-
- DBG("zr364xx_mmap: %ld\n", size);
+ struct zr364xx_camera *cam = video_drvdata(file);
+ int ret;
- if (vdev == NULL)
+ if (cam == NULL) {
+ DBG("%s: cam == NULL\n", __func__);
return -ENODEV;
- cam = video_get_drvdata(vdev);
-
- pos = cam->framebuf;
- while (size > 0) {
- if (vm_insert_page(vma, start, vmalloc_to_page(pos)))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
}
+ DBG("mmap called, vma=0x%08lx\n", (unsigned long)vma);
- return 0;
+ ret = videobuf_mmap_mapper(&cam->vb_vidq, vma);
+
+ DBG("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
+ return ret;
}
+static unsigned int zr364xx_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct zr364xx_camera *cam = video_drvdata(file);
+ struct videobuf_queue *q = &cam->vb_vidq;
+ DBG("%s\n", __func__);
+
+ if (cam->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
@@ -770,6 +1396,7 @@ static const struct v4l2_file_operations
.read = zr364xx_read,
.mmap = zr364xx_mmap,
.ioctl = video_ioctl2,
+ .poll = zr364xx_poll,
};
static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = {
@@ -786,6 +1413,10 @@ static const struct v4l2_ioctl_ops zr364
.vidioc_queryctrl = zr364xx_vidioc_queryctrl,
.vidioc_g_ctrl = zr364xx_vidioc_g_ctrl,
.vidioc_s_ctrl = zr364xx_vidioc_s_ctrl,
+ .vidioc_reqbufs = zr364xx_vidioc_reqbufs,
+ .vidioc_querybuf = zr364xx_vidioc_querybuf,
+ .vidioc_qbuf = zr364xx_vidioc_qbuf,
+ .vidioc_dqbuf = zr364xx_vidioc_dqbuf,
};
static struct video_device zr364xx_template = {
@@ -801,15 +1432,75 @@ static struct video_device zr364xx_templ
/*******************/
/* USB integration */
/*******************/
+static int zr364xx_board_init(struct zr364xx_camera *cam)
+{
+ struct zr364xx_pipeinfo *pipe = cam->pipe;
+ unsigned long i;
+
+ DBG("board init: %p\n", cam);
+ memset(pipe, 0, sizeof(*pipe));
+ pipe->cam = cam;
+ pipe->transfer_size = BUFFER_SIZE;
+
+ pipe->transfer_buffer = kzalloc(pipe->transfer_size,
+ GFP_KERNEL);
+ if (pipe->transfer_buffer == NULL) {
+ DBG("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ cam->b_acquire = 0;
+ cam->frame_count = 0;
+
+ /*** start create system buffers ***/
+ for (i = 0; i < FRAMES; i++) {
+ /* always allocate maximum size for system buffers */
+ cam->buffer.frame[i].lpvbits = vmalloc(MAX_FRAME_SIZE);
+
+ DBG("valloc %p, idx %lu, pdata %p\n",
+ &cam->buffer.frame[i], i,
+ cam->buffer.frame[i].lpvbits);
+ if (cam->buffer.frame[i].lpvbits == NULL) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. "
+ "Using less frames\n");
+ break;
+ }
+ }
+
+ if (i == 0) {
+ printk(KERN_INFO KBUILD_MODNAME ": out of memory. Aborting\n");
+ kfree(cam->pipe->transfer_buffer);
+ return -ENOMEM;
+ } else
+ cam->buffer.dwFrames = i;
+
+ /* make sure internal states are set */
+ for (i = 0; i < FRAMES; i++) {
+ cam->buffer.frame[i].ulState = ZR364XX_READ_IDLE;
+ cam->buffer.frame[i].cur_size = 0;
+ }
+
+ cam->cur_frame = 0;
+ cam->last_frame = -1;
+ /*** end create system buffers ***/
+
+ /* start read pipe */
+ zr364xx_start_readpipe(cam);
+ DBG(": board initialized\n");
+ return 0;
+}
static int zr364xx_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
int err;
+ int i;
- DBG("probing...");
+ DBG("probing...\n");
dev_info(&intf->dev, DRIVER_DESC " compatible webcam plugged\n");
dev_info(&intf->dev, "model %04x:%04x detected\n",
@@ -831,19 +1522,13 @@ static int zr364xx_probe(struct usb_inte
return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
+ cam->vdev->parent = &intf->dev;
video_set_drvdata(cam->vdev, cam);
if (debug)
cam->vdev->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
- if ((cam->buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL)) == NULL) {
- dev_info(&udev->dev, "cam->buffer: out of memory !\n");
- video_device_release(cam->vdev);
- kfree(cam);
- return -ENODEV;
- }
-
switch (mode) {
case 1:
dev_info(&udev->dev, "160x120 mode selected\n");
@@ -870,21 +1555,48 @@ static int zr364xx_probe(struct usb_inte
header2[439] = cam->width / 256;
header2[440] = cam->width % 256;
+ cam->users = 0;
cam->nb = 0;
- cam->brightness = 64;
+ cam->mode.brightness = 64;
mutex_init(&cam->lock);
+ mutex_init(&cam->open_lock);
+ DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
+
+ /* set up the endpoint information */
+ iface_desc = intf->cur_altsetting;
+ DBG("num endpoints %d\n", iface_desc->desc.bNumEndpoints);
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!cam->read_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+ /* we found the bulk in endpoint */
+ cam->read_endpoint = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (!cam->read_endpoint) {
+ dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ return -ENOMEM;
+ }
+
+ /* v4l */
+ INIT_LIST_HEAD(&cam->vidq.active);
+ cam->vidq.cam = cam;
err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
video_device_release(cam->vdev);
- kfree(cam->buffer);
kfree(cam);
return err;
}
usb_set_intfdata(intf, cam);
+ /* load zr364xx board specific */
+ zr364xx_board_init(cam);
+
+ spin_lock_init(&cam->slock);
+
dev_info(&udev->dev, DRIVER_DESC " controlling video device %d\n",
cam->vdev->num);
return 0;
@@ -894,15 +1606,13 @@ static int zr364xx_probe(struct usb_inte
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
+ videobuf_mmap_free(&cam->vb_vidq);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
if (cam->vdev)
video_unregister_device(cam->vdev);
cam->vdev = NULL;
- kfree(cam->buffer);
- if (cam->framebuf)
- vfree(cam->framebuf);
- kfree(cam);
+ zr364xx_destroy(cam);
}
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-03-28 10:11 ` [PATCH] Implement " Lamarque Vieira Souza
@ 2009-03-28 11:44 ` Hans de Goede
2009-03-28 13:09 ` Lamarque Vieira Souza
2009-07-03 2:09 ` Lamarque Vieira Souza
1 sibling, 1 reply; 21+ messages in thread
From: Hans de Goede @ 2009-03-28 11:44 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, video4linux-list, linux-media
On 03/28/2009 11:11 AM, Lamarque Vieira Souza wrote:
> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> converting the driver to use videobuf.
>
> Tested with Creative PC-CAM 880.
>
> It basically:
> . implements V4L2_CAP_STREAMING using videobuf;
>
> . re-implements V4L2_CAP_READWRITE using videobuf;
>
> . copies cam->udev->product to the card field of the v4l2_capability struct.
> That gives more information to the users about the webcam;
>
> . moves the brightness setting code from before requesting a frame (in
> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> executed only when the application requests a change in brightness and
> not before every frame read;
>
> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> libv4l do not work.
>
Note that this may make things work, but is not correct, applications
which properly honor the field value may get bitten by this. The correct
fix is to unconditionally set the field value to V4L2_FIELD_NONE.
> This patch fixes zr364xx for applications such as mplayer,
> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> with zr364xx chip.
>
> Signed-off-by: Lamarque V. Souza<lamarque@gmail.com>
<snip>
Regards,
Hans
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-03-28 11:44 ` Hans de Goede
@ 2009-03-28 13:09 ` Lamarque Vieira Souza
0 siblings, 0 replies; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-03-28 13:09 UTC (permalink / raw)
To: Hans de Goede; +Cc: Mauro Carvalho Chehab, video4linux-list, linux-media
Em Saturday 28 March 2009, Hans de Goede escreveu:
> On 03/28/2009 11:11 AM, Lamarque Vieira Souza wrote:
> > This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> > converting the driver to use videobuf.
> >
> > Tested with Creative PC-CAM 880.
> >
> > It basically:
> > . implements V4L2_CAP_STREAMING using videobuf;
> >
> > . re-implements V4L2_CAP_READWRITE using videobuf;
> >
> > . copies cam->udev->product to the card field of the v4l2_capability
> > struct. That gives more information to the users about the webcam;
> >
> > . moves the brightness setting code from before requesting a frame (in
> > read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> > executed only when the application requests a change in brightness and
> > not before every frame read;
> >
> > . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> > libv4l do not work.
>
> Note that this may make things work, but is not correct, applications
> which properly honor the field value may get bitten by this. The correct
> fix is to unconditionally set the field value to V4L2_FIELD_NONE.
The part of zr364xx_vidioc_try_fmt_vid_cap which was commented was the "if"
that checks the field value, now the driver does not do the check, it always
set the field value to V4L2_FIELD_NONE, since that is the only value that the
card accepts.
> > This patch fixes zr364xx for applications such as mplayer,
> > Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> > with zr364xx chip.
> >
> > Signed-off-by: Lamarque V. Souza<lamarque@gmail.com>
>
> <snip>
>
> Regards,
>
> Hans
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-03-28 10:11 ` [PATCH] Implement " Lamarque Vieira Souza
2009-03-28 11:44 ` Hans de Goede
@ 2009-07-03 2:09 ` Lamarque Vieira Souza
2009-07-11 20:29 ` Lamarque Vieira Souza
1 sibling, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-03 2:09 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Antoine Jacquet, linux-media, video4linux-list
Hi all,
I have noticed the patch mentioned in the subject was not included in 2.6.30.
Do you plan to add it to 2.6.31?
Em Saturday 28 March 2009, Lamarque Vieira Souza escreveu:
> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> converting the driver to use videobuf.
>
> Tested with Creative PC-CAM 880.
>
> It basically:
> . implements V4L2_CAP_STREAMING using videobuf;
>
> . re-implements V4L2_CAP_READWRITE using videobuf;
>
> . copies cam->udev->product to the card field of the v4l2_capability
> struct. That gives more information to the users about the webcam;
>
> . moves the brightness setting code from before requesting a frame (in
> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> executed only when the application requests a change in brightness and
> not before every frame read;
>
> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> libv4l do not work.
>
> This patch fixes zr364xx for applications such as mplayer,
> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> with zr364xx chip.
>
> Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> ---
>
> --- v4l-dvb/linux/drivers/media/video/zr364xx.c 2009-03-27
> 15:18:54.050413997 -0300
> +++ v4l-dvb/linux-lvs/drivers/media/video/zr364xx.c 2009-03-27
> 15:22:47.914414277 -0300
... stripped off to not bloat the e-mail.
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-03 2:09 ` Lamarque Vieira Souza
@ 2009-07-11 20:29 ` Lamarque Vieira Souza
2009-07-15 20:35 ` Antoine Jacquet
0 siblings, 1 reply; 21+ messages in thread
From: Lamarque Vieira Souza @ 2009-07-11 20:29 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: Antoine Jacquet, linux-media, video4linux-list
Hi guys. Any news about this patch? I really think is important to make
zr364xx driver works with libv4l, mplayer, kopete and skype. Maintaining this
patch out of tree is also troublesome for me, I would really appreciate if you
could add it to the tree. If there is any problem with the patch let me know
that will fix it.
Em Thursday 02 July 2009, Lamarque Vieira Souza escreveu:
> Hi all,
>
> I have noticed the patch mentioned in the subject was not included in
> 2.6.30. Do you plan to add it to 2.6.31?
>
> Em Saturday 28 March 2009, Lamarque Vieira Souza escreveu:
> > This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
> > converting the driver to use videobuf.
> >
> > Tested with Creative PC-CAM 880.
> >
> > It basically:
> > . implements V4L2_CAP_STREAMING using videobuf;
> >
> > . re-implements V4L2_CAP_READWRITE using videobuf;
> >
> > . copies cam->udev->product to the card field of the v4l2_capability
> > struct. That gives more information to the users about the webcam;
> >
> > . moves the brightness setting code from before requesting a frame (in
> > read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
> > executed only when the application requests a change in brightness and
> > not before every frame read;
> >
> > . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
> > libv4l do not work.
> >
> > This patch fixes zr364xx for applications such as mplayer,
> > Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
> > with zr364xx chip.
> >
> > Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
> > ---
> >
> > --- v4l-dvb/linux/drivers/media/video/zr364xx.c 2009-03-27
> > 15:18:54.050413997 -0300
> > +++ v4l-dvb/linux-lvs/drivers/media/video/zr364xx.c 2009-03-27
> > 15:22:47.914414277 -0300
>
> ... stripped off to not bloat the e-mail.
--
Lamarque V. Souza
http://www.geographicguide.com/brazil.htm
Linux User #57137 - http://counter.li.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver
2009-07-11 20:29 ` Lamarque Vieira Souza
@ 2009-07-15 20:35 ` Antoine Jacquet
0 siblings, 0 replies; 21+ messages in thread
From: Antoine Jacquet @ 2009-07-15 20:35 UTC (permalink / raw)
To: Lamarque Vieira Souza
Cc: Mauro Carvalho Chehab, linux-media, video4linux-list
Hi,
Sorry for the very late answer, I did not have time to work on my driver
during the past months.
I managed to apply your patch to my current hg tree, but since it is 5
months out of sync with the main tree, I am having issues to merge your
work.
Could you send a patch against the current main tree (
http://linuxtv.org/hg/v4l-dvb/ ) so I can test your patch?
Thanks a lot and sorry again.
Regards,
Antoine
Lamarque Vieira Souza wrote:
> Hi guys. Any news about this patch? I really think is important to make
> zr364xx driver works with libv4l, mplayer, kopete and skype. Maintaining this
> patch out of tree is also troublesome for me, I would really appreciate if you
> could add it to the tree. If there is any problem with the patch let me know
> that will fix it.
>
> Em Thursday 02 July 2009, Lamarque Vieira Souza escreveu:
>> Hi all,
>>
>> I have noticed the patch mentioned in the subject was not included in
>> 2.6.30. Do you plan to add it to 2.6.31?
>>
>> Em Saturday 28 March 2009, Lamarque Vieira Souza escreveu:
>>> This patch implements V4L2_CAP_STREAMING for the zr364xx driver, by
>>> converting the driver to use videobuf.
>>>
>>> Tested with Creative PC-CAM 880.
>>>
>>> It basically:
>>> . implements V4L2_CAP_STREAMING using videobuf;
>>>
>>> . re-implements V4L2_CAP_READWRITE using videobuf;
>>>
>>> . copies cam->udev->product to the card field of the v4l2_capability
>>> struct. That gives more information to the users about the webcam;
>>>
>>> . moves the brightness setting code from before requesting a frame (in
>>> read_frame) to the vidioc_s_ctrl ioctl. This way the brightness code is
>>> executed only when the application requests a change in brightness and
>>> not before every frame read;
>>>
>>> . comments part of zr364xx_vidioc_try_fmt_vid_cap that says that Skype +
>>> libv4l do not work.
>>>
>>> This patch fixes zr364xx for applications such as mplayer,
>>> Kopete+libv4l and Skype+libv4l can make use of the webcam that comes
>>> with zr364xx chip.
>>>
>>> Signed-off-by: Lamarque V. Souza <lamarque@gmail.com>
>>> ---
>>>
>>> --- v4l-dvb/linux/drivers/media/video/zr364xx.c 2009-03-27
>>> 15:18:54.050413997 -0300
>>> +++ v4l-dvb/linux-lvs/drivers/media/video/zr364xx.c 2009-03-27
>>> 15:22:47.914414277 -0300
>> ... stripped off to not bloat the e-mail.
>
>
--
Antoine "Royale" Jacquet
http://royale.zerezo.com
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2009-07-22 23:58 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-07-15 23:54 [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Lamarque Vieira Souza
2009-07-16 12:59 ` Antoine Jacquet
2009-07-16 13:58 ` Lamarque Vieira Souza
2009-07-16 15:45 ` Mauro Carvalho Chehab
2009-07-16 15:56 ` Force driver to load (tcm825x) Jesko Schwarzer
2009-07-16 16:42 ` [PATCH] Implement V4L2_CAP_STREAMING for zr364xx driver Karicheri, Muralidharan
2009-07-16 20:09 ` Lamarque Vieira Souza
2009-07-17 23:50 ` Antoine Jacquet
2009-07-20 23:46 ` [PATCH] Implement changing resolution on the fly " Lamarque Vieira Souza
2009-07-21 14:29 ` Antoine Jacquet
2009-07-21 15:14 ` Lamarque Vieira Souza
2009-07-21 22:42 ` Lamarque Vieira Souza
2009-07-22 19:31 ` Antoine Jacquet
2009-07-22 19:54 ` Lamarque Vieira Souza
2009-07-22 23:58 ` Antoine Jacquet
-- strict thread matches above, loose matches on Subject: below --
2009-03-25 23:25 Patch implementing V4L2_CAP_STREAMING " Lamarque Vieira Souza
2009-03-27 18:39 ` Lamarque Vieira Souza
2009-03-28 9:34 ` Mauro Carvalho Chehab
2009-03-28 10:11 ` [PATCH] Implement " Lamarque Vieira Souza
2009-03-28 11:44 ` Hans de Goede
2009-03-28 13:09 ` Lamarque Vieira Souza
2009-07-03 2:09 ` Lamarque Vieira Souza
2009-07-11 20:29 ` Lamarque Vieira Souza
2009-07-15 20:35 ` Antoine Jacquet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox