diff options
Diffstat (limited to 'linux/drivers/media/video/zr364xx.c')
-rw-r--r-- | linux/drivers/media/video/zr364xx.c | 127 |
1 files changed, 88 insertions, 39 deletions
diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index 7dff47834..c298ce625 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -29,6 +29,7 @@ #include <linux/module.h> +#include <linux/version.h> #include <linux/init.h> #include <linux/usb.h> #include <linux/vmalloc.h> @@ -43,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 @@ -66,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 @@ -375,7 +383,7 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count, static void free_buffer(struct videobuf_queue *vq, struct zr364xx_buffer *buf) { - DBG("%s\n", __func__); + _DBG("%s\n", __func__); if (in_interrupt()) BUG(); @@ -428,7 +436,7 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) 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); @@ -440,7 +448,7 @@ static void buffer_release(struct videobuf_queue *vq, struct zr364xx_buffer *buf = container_of(vb, struct zr364xx_buffer, vb); - DBG("%s\n", __func__); + _DBG("%s\n", __func__); free_buffer(vq, buf); } @@ -462,7 +470,7 @@ static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t count, { struct zr364xx_camera *cam = video_drvdata(file); - DBG("%s\n", __func__); + _DBG("%s\n", __func__); if (!buf) return -EINVAL; @@ -582,7 +590,7 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, 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]; @@ -600,12 +608,6 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, 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; @@ -613,7 +615,7 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, 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; @@ -631,21 +633,28 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, 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 */ @@ -680,7 +689,7 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, 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]); @@ -707,7 +716,7 @@ static int res_get(struct zr364xx_camera *cam) } /* it's free, grab it */ cam->resources = 1; - DBG("res: get\n"); + _DBG("res: get\n"); mutex_unlock(&cam->lock); return 1; } @@ -722,7 +731,7 @@ static void res_free(struct zr364xx_camera *cam) 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, @@ -734,7 +743,7 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, 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 +883,13 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, 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; @@ -907,7 +920,6 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, 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 +927,7 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, 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 +940,55 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, 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: @@ -972,7 +1025,7 @@ static int zr364xx_vidioc_qbuf(struct file *file, { 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; } @@ -983,7 +1036,7 @@ static int zr364xx_vidioc_dqbuf(struct file *file, { 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; } @@ -995,7 +1048,7 @@ static void read_pipe_completion(struct urb *purb) 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; @@ -1106,7 +1159,6 @@ static void zr364xx_stop_readpipe(struct zr364xx_camera *cam) pipe_info->stream_urb = NULL; } } - DBG("stop read pipe\n"); return; } @@ -1123,6 +1175,7 @@ static int zr364xx_start_acquire(struct zr364xx_camera *cam) cam->buffer.frame[j].ulState = ZR364XX_READ_IDLE; cam->buffer.frame[j].cur_size = 0; } + cam->b_acquire = 1; return 0; } @@ -1165,11 +1218,9 @@ static int zr364xx_vidioc_streamon(struct file *file, void *priv, 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; } @@ -1281,8 +1332,6 @@ static void zr364xx_destroy(struct zr364xx_camera *cam) /* 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; @@ -1363,7 +1412,7 @@ static unsigned int zr364xx_poll(struct file *file, { 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; |