Commit 96b8e145 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (10703): zoran: convert to video_ioctl2 and remove 'ready_to_be_freed' hack.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 17bdd9dd
...@@ -312,7 +312,6 @@ struct zoran_jpg_struct { ...@@ -312,7 +312,6 @@ struct zoran_jpg_struct {
struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME]; /* buffers */ struct zoran_jpg_buffer buffer[BUZ_MAX_FRAME]; /* buffers */
int num_buffers, buffer_size; int num_buffers, buffer_size;
u8 allocated; /* Flag if buffers are allocated */ u8 allocated; /* Flag if buffers are allocated */
u8 ready_to_be_freed; /* hack - see zoran_driver.c */
u8 need_contiguous; /* Flag if contiguous buffers are needed */ u8 need_contiguous; /* Flag if contiguous buffers are needed */
}; };
...@@ -321,7 +320,6 @@ struct zoran_v4l_struct { ...@@ -321,7 +320,6 @@ struct zoran_v4l_struct {
struct zoran_v4l_buffer buffer[VIDEO_MAX_FRAME]; /* buffers */ struct zoran_v4l_buffer buffer[VIDEO_MAX_FRAME]; /* buffers */
int num_buffers, buffer_size; int num_buffers, buffer_size;
u8 allocated; /* Flag if buffers are allocated */ u8 allocated; /* Flag if buffers are allocated */
u8 ready_to_be_freed; /* hack - see zoran_driver.c */
}; };
struct zoran; struct zoran;
......
...@@ -309,11 +309,6 @@ v4l_fbuffer_alloc (struct file *file) ...@@ -309,11 +309,6 @@ v4l_fbuffer_alloc (struct file *file)
unsigned char *mem; unsigned char *mem;
unsigned long pmem = 0; unsigned long pmem = 0;
/* we might have old buffers lying around... */
if (fh->v4l_buffers.ready_to_be_freed) {
v4l_fbuffer_free(file);
}
for (i = 0; i < fh->v4l_buffers.num_buffers; i++) { for (i = 0; i < fh->v4l_buffers.num_buffers; i++) {
if (fh->v4l_buffers.buffer[i].fbuffer) if (fh->v4l_buffers.buffer[i].fbuffer)
dprintk(2, dprintk(2,
...@@ -421,7 +416,6 @@ v4l_fbuffer_free (struct file *file) ...@@ -421,7 +416,6 @@ v4l_fbuffer_free (struct file *file)
} }
fh->v4l_buffers.allocated = 0; fh->v4l_buffers.allocated = 0;
fh->v4l_buffers.ready_to_be_freed = 0;
} }
/* /*
...@@ -466,11 +460,6 @@ jpg_fbuffer_alloc (struct file *file) ...@@ -466,11 +460,6 @@ jpg_fbuffer_alloc (struct file *file)
int i, j, off; int i, j, off;
unsigned long mem; unsigned long mem;
/* we might have old buffers lying around */
if (fh->jpg_buffers.ready_to_be_freed) {
jpg_fbuffer_free(file);
}
for (i = 0; i < fh->jpg_buffers.num_buffers; i++) { for (i = 0; i < fh->jpg_buffers.num_buffers; i++) {
if (fh->jpg_buffers.buffer[i].frag_tab) if (fh->jpg_buffers.buffer[i].frag_tab)
dprintk(2, dprintk(2,
...@@ -613,7 +602,6 @@ jpg_fbuffer_free (struct file *file) ...@@ -613,7 +602,6 @@ jpg_fbuffer_free (struct file *file)
} }
fh->jpg_buffers.allocated = 0; fh->jpg_buffers.allocated = 0;
fh->jpg_buffers.ready_to_be_freed = 0;
} }
/* /*
...@@ -657,7 +645,7 @@ zoran_v4l_set_format (struct file *file, ...@@ -657,7 +645,7 @@ zoran_v4l_set_format (struct file *file,
if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) {
dprintk(1, dprintk(1,
KERN_ERR KERN_ERR
"%s: v4l_set_format() - wrong frame alingment\n", "%s: v4l_set_format() - wrong frame alignment\n",
ZR_DEVNAME(zr)); ZR_DEVNAME(zr));
return -EINVAL; return -EINVAL;
} }
...@@ -1122,7 +1110,6 @@ zoran_open_init_session (struct file *file) ...@@ -1122,7 +1110,6 @@ zoran_open_init_session (struct file *file)
fh->v4l_buffers.buffer[i].bs.frame = i; fh->v4l_buffers.buffer[i].bs.frame = i;
} }
fh->v4l_buffers.allocated = 0; fh->v4l_buffers.allocated = 0;
fh->v4l_buffers.ready_to_be_freed = 0;
fh->v4l_buffers.active = ZORAN_FREE; fh->v4l_buffers.active = ZORAN_FREE;
fh->v4l_buffers.buffer_size = v4l_bufsize; fh->v4l_buffers.buffer_size = v4l_bufsize;
fh->v4l_buffers.num_buffers = v4l_nbufs; fh->v4l_buffers.num_buffers = v4l_nbufs;
...@@ -1138,7 +1125,6 @@ zoran_open_init_session (struct file *file) ...@@ -1138,7 +1125,6 @@ zoran_open_init_session (struct file *file)
} }
fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous; fh->jpg_buffers.need_contiguous = zr->jpg_buffers.need_contiguous;
fh->jpg_buffers.allocated = 0; fh->jpg_buffers.allocated = 0;
fh->jpg_buffers.ready_to_be_freed = 0;
fh->jpg_buffers.active = ZORAN_FREE; fh->jpg_buffers.active = ZORAN_FREE;
fh->jpg_buffers.buffer_size = jpg_bufsize; fh->jpg_buffers.buffer_size = jpg_bufsize;
fh->jpg_buffers.num_buffers = jpg_nbufs; fh->jpg_buffers.num_buffers = jpg_nbufs;
...@@ -1172,10 +1158,8 @@ zoran_close_end_session (struct file *file) ...@@ -1172,10 +1158,8 @@ zoran_close_end_session (struct file *file)
} }
/* v4l buffers */ /* v4l buffers */
if (fh->v4l_buffers.allocated || if (fh->v4l_buffers.allocated)
fh->v4l_buffers.ready_to_be_freed) {
v4l_fbuffer_free(file); v4l_fbuffer_free(file);
}
/* jpg capture */ /* jpg capture */
if (fh->jpg_buffers.active != ZORAN_FREE) { if (fh->jpg_buffers.active != ZORAN_FREE) {
...@@ -1186,10 +1170,8 @@ zoran_close_end_session (struct file *file) ...@@ -1186,10 +1170,8 @@ zoran_close_end_session (struct file *file)
} }
/* jpg buffers */ /* jpg buffers */
if (fh->jpg_buffers.allocated || if (fh->jpg_buffers.allocated)
fh->jpg_buffers.ready_to_be_freed) {
jpg_fbuffer_free(file); jpg_fbuffer_free(file);
}
} }
/* /*
...@@ -1903,38 +1885,13 @@ zoran_set_input (struct zoran *zr, ...@@ -1903,38 +1885,13 @@ zoran_set_input (struct zoran *zr,
* ioctl routine * ioctl routine
*/ */
static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) static long zoran_default(struct file *file, void *__fh, int cmd, void *arg)
{ {
struct zoran_fh *fh = file->private_data; struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr; struct zoran *zr = fh->zr;
/* CAREFUL: used in multiple places here */
struct zoran_jpg_settings settings; struct zoran_jpg_settings settings;
/* we might have older buffers lying around... We don't want
* to wait, but we do want to try cleaning them up ASAP. So
* we try to obtain the lock and free them. If that fails, we
* don't do anything and wait for the next turn. In the end,
* zoran_close() or a new allocation will still free them...
* This is just a 'the sooner the better' extra 'feature'
*
* We don't free the buffers right on munmap() because that
* causes oopses (kfree() inside munmap() oopses for no
* apparent reason - it's also not reproduceable in any way,
* but moving the free code outside the munmap() handler fixes
* all this... If someone knows why, please explain me (Ronald)
*/
if (mutex_trylock(&zr->resource_lock)) {
/* we obtained it! Let's try to free some things */
if (fh->jpg_buffers.ready_to_be_freed)
jpg_fbuffer_free(file);
if (fh->v4l_buffers.ready_to_be_freed)
v4l_fbuffer_free(file);
mutex_unlock(&zr->resource_lock);
}
switch (cmd) { switch (cmd) {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
struct video_capability *vcap = arg; struct video_capability *vcap = arg;
...@@ -1956,7 +1913,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -1956,7 +1913,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
case VIDIOCGCHAN: case VIDIOCGCHAN:
{ {
...@@ -1987,7 +1943,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -1987,7 +1943,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
/* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says: /* RJ: the documentation at http://roadrunner.swansea.linux.org.uk/v4lapi.shtml says:
* *
...@@ -2017,11 +1972,10 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2017,11 +1972,10 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Make sure the changes come into effect */ /* Make sure the changes come into effect */
res = wait_grab_pending(zr); res = wait_grab_pending(zr);
schan_unlock_and_return: schan_unlock_and_return:
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return res; return res;
} }
break;
case VIDIOCGPICT: case VIDIOCGPICT:
{ {
...@@ -2045,7 +1999,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2045,7 +1999,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
case VIDIOCSPICT: case VIDIOCSPICT:
{ {
...@@ -2091,7 +2044,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2091,7 +2044,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
case VIDIOCCAPTURE: case VIDIOCCAPTURE:
{ {
...@@ -2106,7 +2058,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2106,7 +2058,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case VIDIOCGWIN: case VIDIOCGWIN:
{ {
...@@ -2124,7 +2075,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2124,7 +2075,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
vwin->clipcount = 0; vwin->clipcount = 0;
return 0; return 0;
} }
break;
case VIDIOCSWIN: case VIDIOCSWIN:
{ {
...@@ -2146,7 +2096,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2146,7 +2096,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case VIDIOCGFBUF: case VIDIOCGFBUF:
{ {
...@@ -2159,7 +2108,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2159,7 +2108,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return 0; return 0;
} }
break;
case VIDIOCSFBUF: case VIDIOCSFBUF:
{ {
...@@ -2192,7 +2140,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2192,7 +2140,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case VIDIOCSYNC: case VIDIOCSYNC:
{ {
...@@ -2208,7 +2155,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2208,7 +2155,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
zr->v4l_sync_tail++; zr->v4l_sync_tail++;
return res; return res;
} }
break;
case VIDIOCMCAPTURE: case VIDIOCMCAPTURE:
{ {
...@@ -2226,7 +2172,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2226,7 +2172,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return res; return res;
} }
break;
case VIDIOCGMBUF: case VIDIOCGMBUF:
{ {
...@@ -2262,12 +2207,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2262,12 +2207,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* The next mmap will map the V4L buffers */ /* The next mmap will map the V4L buffers */
fh->map_mode = ZORAN_MAP_MODE_RAW; fh->map_mode = ZORAN_MAP_MODE_RAW;
v4l1reqbuf_unlock_and_return: v4l1reqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return res; return res;
} }
break;
case VIDIOCGUNIT: case VIDIOCGUNIT:
{ {
...@@ -2283,7 +2227,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2283,7 +2227,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
/* /*
* RJ: In principal we could support subcaptures for V4L grabbing. * RJ: In principal we could support subcaptures for V4L grabbing.
...@@ -2297,7 +2240,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2297,7 +2240,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ZR_DEVNAME(zr)); ZR_DEVNAME(zr));
return -EINVAL; return -EINVAL;
} }
break;
case VIDIOCSCAPTURE: case VIDIOCSCAPTURE:
{ {
...@@ -2305,7 +2247,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2305,7 +2247,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ZR_DEVNAME(zr)); ZR_DEVNAME(zr));
return -EINVAL; return -EINVAL;
} }
break;
case BUZIOC_G_PARAMS: case BUZIOC_G_PARAMS:
{ {
...@@ -2352,7 +2293,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2352,7 +2293,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return 0; return 0;
} }
break;
case BUZIOC_S_PARAMS: case BUZIOC_S_PARAMS:
{ {
...@@ -2401,12 +2341,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2401,12 +2341,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
} }
fh->jpg_settings = settings; fh->jpg_settings = settings;
sparams_unlock_and_return: sparams_unlock_and_return:
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return res; return res;
} }
break;
case BUZIOC_REQBUFS: case BUZIOC_REQBUFS:
{ {
...@@ -2456,12 +2395,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2456,12 +2395,11 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* The next mmap will map the MJPEG buffers - could /* The next mmap will map the MJPEG buffers - could
* also be *_PLAY, but it doesn't matter here */ * also be *_PLAY, but it doesn't matter here */
fh->map_mode = ZORAN_MAP_MODE_JPG_REC; fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
jpgreqbuf_unlock_and_return: jpgreqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return res; return res;
} }
break;
case BUZIOC_QBUF_CAPT: case BUZIOC_QBUF_CAPT:
{ {
...@@ -2476,7 +2414,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2476,7 +2414,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case BUZIOC_QBUF_PLAY: case BUZIOC_QBUF_PLAY:
{ {
...@@ -2491,7 +2428,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2491,7 +2428,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case BUZIOC_SYNC: case BUZIOC_SYNC:
{ {
...@@ -2506,7 +2442,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2506,7 +2442,6 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
case BUZIOC_G_STATUS: case BUZIOC_G_STATUS:
{ {
...@@ -2550,7 +2485,7 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2550,7 +2485,7 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
input = zr->card.input[zr->input].muxsel; input = zr->card.input[zr->input].muxsel;
decoder_command(zr, DECODER_SET_INPUT, &input); decoder_command(zr, DECODER_SET_INPUT, &input);
decoder_command(zr, DECODER_SET_NORM, &zr->norm); decoder_command(zr, DECODER_SET_NORM, &zr->norm);
gstat_unlock_and_return: gstat_unlock_and_return:
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
if (!res) { if (!res) {
...@@ -2569,1599 +2504,1297 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg) ...@@ -2569,1599 +2504,1297 @@ static long zoran_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return res; return res;
} }
break;
/* The new video4linux2 capture interface - much nicer than video4linux1, since
* it allows for integrating the JPEG capturing calls inside standard v4l2
*/
case VIDIOC_QUERYCAP:
{
struct v4l2_capability *cap = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
memset(cap, 0, sizeof(*cap)); default:
strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1); return -EINVAL;
strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
cap->version =
KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
RELEASE_VERSION);
cap->capabilities = ZORAN_V4L2_VID_FLAGS;
return 0;
} }
break; }
case VIDIOC_ENUM_FMT:
{
struct v4l2_fmtdesc *fmt = arg;
int index = fmt->index, num = -1, i, flag = 0, type =
fmt->type;
dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUM_FMT - index=%d\n", static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
ZR_DEVNAME(zr), fmt->index); {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
switch (fmt->type) { memset(cap, 0, sizeof(*cap));
case V4L2_BUF_TYPE_VIDEO_CAPTURE: strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
flag = ZORAN_FORMAT_CAPTURE; strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
break; snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
case V4L2_BUF_TYPE_VIDEO_OUTPUT: pci_name(zr->pci_dev));
flag = ZORAN_FORMAT_PLAYBACK; cap->version =
break; KERNEL_VERSION(MAJOR_VERSION, MINOR_VERSION,
case V4L2_BUF_TYPE_VIDEO_OVERLAY: RELEASE_VERSION);
flag = ZORAN_FORMAT_OVERLAY; cap->capabilities = ZORAN_V4L2_VID_FLAGS;
break;
default:
dprintk(1,
KERN_ERR
"%s: VIDIOC_ENUM_FMT - unknown type %d\n",
ZR_DEVNAME(zr), fmt->type);
return -EINVAL;
}
for (i = 0; i < NUM_FORMATS; i++) { return 0;
if (zoran_formats[i].flags & flag) }
num++;
if (num == fmt->index)
break;
}
if (fmt->index < 0 /* late, but not too late */ ||
i == NUM_FORMATS)
return -EINVAL;
memset(fmt, 0, sizeof(*fmt)); static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag)
fmt->index = index; {
fmt->type = type; int num = -1, i;
strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
fmt->pixelformat = zoran_formats[i].fourcc;
if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
return 0; for (i = 0; i < NUM_FORMATS; i++) {
if (zoran_formats[i].flags & flag)
num++;
if (num == fmt->index)
break;
} }
break; if (fmt->index < 0 /* late, but not too late */ || i == NUM_FORMATS)
return -EINVAL;
case VIDIOC_G_FMT:
{
struct v4l2_format *fmt = arg;
int type = fmt->type;
dprintk(5, KERN_DEBUG "%s: VIDIOC_G_FMT\n", ZR_DEVNAME(zr)); strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
fmt->pixelformat = zoran_formats[i].fourcc;
if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
return 0;
}
memset(fmt, 0, sizeof(*fmt)); static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh,
fmt->type = type; struct v4l2_fmtdesc *f)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
switch (fmt->type) { return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE);
case V4L2_BUF_TYPE_VIDEO_OVERLAY: }
mutex_lock(&zr->resource_lock); static int zoran_enum_fmt_vid_out(struct file *file, void *__fh,
struct v4l2_fmtdesc *f)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
fmt->fmt.win.w.left = fh->overlay_settings.x; return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK);
fmt->fmt.win.w.top = fh->overlay_settings.y; }
fmt->fmt.win.w.width = fh->overlay_settings.width;
fmt->fmt.win.w.height =
fh->overlay_settings.height;
if (fh->overlay_settings.width * 2 >
BUZ_MAX_HEIGHT)
fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
else
fmt->fmt.win.field = V4L2_FIELD_TOP;
mutex_unlock(&zr->resource_lock); static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh,
struct v4l2_fmtdesc *f)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
break; return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY);
}
case V4L2_BUF_TYPE_VIDEO_CAPTURE: static int zoran_g_fmt_vid_out(struct file *file, void *__fh,
case V4L2_BUF_TYPE_VIDEO_OUTPUT: struct v4l2_format *fmt)
{
mutex_lock(&zr->resource_lock); struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
fh->map_mode == ZORAN_MAP_MODE_RAW) {
fmt->fmt.pix.width =
fh->v4l_settings.width;
fmt->fmt.pix.height =
fh->v4l_settings.height;
fmt->fmt.pix.sizeimage =
fh->v4l_settings.bytesperline *
fh->v4l_settings.height;
fmt->fmt.pix.pixelformat =
fh->v4l_settings.format->fourcc;
fmt->fmt.pix.colorspace =
fh->v4l_settings.format->colorspace;
fmt->fmt.pix.bytesperline =
fh->v4l_settings.bytesperline;
if (BUZ_MAX_HEIGHT <
(fh->v4l_settings.height * 2))
fmt->fmt.pix.field =
V4L2_FIELD_INTERLACED;
else
fmt->fmt.pix.field =
V4L2_FIELD_TOP;
} else { mutex_lock(&zr->resource_lock);
fmt->fmt.pix.width = fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm;
fh->jpg_settings.img_width / fmt->fmt.pix.height = fh->jpg_settings.img_height /
fh->jpg_settings.HorDcm; (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm);
fmt->fmt.pix.height = fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fh->jpg_settings.img_height / fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
(fh->jpg_settings.VerDcm * if (fh->jpg_settings.TmpDcm == 1)
fh->jpg_settings.TmpDcm); fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
fmt->fmt.pix.sizeimage = V4L2_FIELD_SEQ_BT : V4L2_FIELD_SEQ_BT);
zoran_v4l2_calc_bufsize(&fh-> else
jpg_settings); fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
fmt->fmt.pix.pixelformat = V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
V4L2_PIX_FMT_MJPEG; fmt->fmt.pix.bytesperline = 0;
if (fh->jpg_settings.TmpDcm == 1) fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_SEQ_BT :
V4L2_FIELD_SEQ_BT);
else
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_TOP :
V4L2_FIELD_BOTTOM);
fmt->fmt.pix.bytesperline = 0;
fmt->fmt.pix.colorspace =
V4L2_COLORSPACE_SMPTE170M;
}
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return 0;
}
break; static int zoran_g_fmt_vid_cap(struct file *file, void *__fh,
struct v4l2_format *fmt)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
default: if (fh->map_mode != ZORAN_MAP_MODE_RAW)
dprintk(1, return zoran_g_fmt_vid_out(file, fh, fmt);
KERN_ERR
"%s: VIDIOC_G_FMT - unsupported type %d\n",
ZR_DEVNAME(zr), fmt->type);
return -EINVAL;
}
return 0;
}
break;
case VIDIOC_S_FMT: mutex_lock(&zr->resource_lock);
{ fmt->fmt.pix.width = fh->v4l_settings.width;
struct v4l2_format *fmt = arg; fmt->fmt.pix.height = fh->v4l_settings.height;
int i, res = 0; fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline *
__le32 printformat; fh->v4l_settings.height;
fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc;
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_FMT - type=%d, ", fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
ZR_DEVNAME(zr), fmt->type); fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
switch (fmt->type) { fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
case V4L2_BUF_TYPE_VIDEO_OVERLAY: else
fmt->fmt.pix.field = V4L2_FIELD_TOP;
dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n", mutex_unlock(&zr->resource_lock);
fmt->fmt.win.w.left, fmt->fmt.win.w.top, return 0;
fmt->fmt.win.w.width, }
fmt->fmt.win.w.height,
fmt->fmt.win.clipcount,
fmt->fmt.win.bitmap);
mutex_lock(&zr->resource_lock);
res =
setup_window(file, fmt->fmt.win.w.left,
fmt->fmt.win.w.top,
fmt->fmt.win.w.width,
fmt->fmt.win.w.height,
(struct video_clip __user *)
fmt->fmt.win.clips,
fmt->fmt.win.clipcount,
fmt->fmt.win.bitmap);
mutex_unlock(&zr->resource_lock);
return res;
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE: static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh,
case V4L2_BUF_TYPE_VIDEO_OUTPUT: struct v4l2_format *fmt)
{
printformat = struct zoran_fh *fh = __fh;
__cpu_to_le32(fmt->fmt.pix.pixelformat); struct zoran *zr = fh->zr;
dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
fmt->fmt.pix.width, fmt->fmt.pix.height,
fmt->fmt.pix.pixelformat,
(char *) &printformat);
/* we can be requested to do JPEG/raw playback/capture */
if (!
(fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
(fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
fmt->fmt.pix.pixelformat ==
V4L2_PIX_FMT_MJPEG))) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FMT - unknown type %d/0x%x(%4.4s) combination\n",
ZR_DEVNAME(zr), fmt->type,
fmt->fmt.pix.pixelformat,
(char *) &printformat);
return -EINVAL;
}
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { mutex_lock(&zr->resource_lock);
mutex_lock(&zr->resource_lock);
settings = fh->jpg_settings; fmt->fmt.win.w.left = fh->overlay_settings.x;
fmt->fmt.win.w.top = fh->overlay_settings.y;
fmt->fmt.win.w.width = fh->overlay_settings.width;
fmt->fmt.win.w.height = fh->overlay_settings.height;
if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT)
fmt->fmt.win.field = V4L2_FIELD_INTERLACED;
else
fmt->fmt.win.field = V4L2_FIELD_TOP;
if (fh->v4l_buffers.allocated || mutex_unlock(&zr->resource_lock);
fh->jpg_buffers.allocated) { return 0;
dprintk(1, }
KERN_ERR
"%s: VIDIOC_S_FMT - cannot change capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto sfmtjpg_unlock_and_return;
}
/* we actually need to set 'real' parameters now */ static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh,
if ((fmt->fmt.pix.height * 2) > struct v4l2_format *fmt)
BUZ_MAX_HEIGHT) {
settings.TmpDcm = 1; struct zoran_fh *fh = __fh;
else struct zoran *zr = fh->zr;
settings.TmpDcm = 2;
settings.decimation = 0;
if (fmt->fmt.pix.height <=
fh->jpg_settings.img_height / 2)
settings.VerDcm = 2;
else
settings.VerDcm = 1;
if (fmt->fmt.pix.width <=
fh->jpg_settings.img_width / 4)
settings.HorDcm = 4;
else if (fmt->fmt.pix.width <=
fh->jpg_settings.img_width / 2)
settings.HorDcm = 2;
else
settings.HorDcm = 1;
if (settings.TmpDcm == 1)
settings.field_per_buff = 2;
else
settings.field_per_buff = 1;
/* check */
if ((res =
zoran_check_jpg_settings(zr,
&settings)))
goto sfmtjpg_unlock_and_return;
/* it's ok, so set them */
fh->jpg_settings = settings;
/* tell the user what we actually did */
fmt->fmt.pix.width =
settings.img_width / settings.HorDcm;
fmt->fmt.pix.height =
settings.img_height * 2 /
(settings.TmpDcm * settings.VerDcm);
if (settings.TmpDcm == 1)
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_SEQ_TB :
V4L2_FIELD_SEQ_BT);
else
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_TOP :
V4L2_FIELD_BOTTOM);
fh->jpg_buffers.buffer_size =
zoran_v4l2_calc_bufsize(&fh->
jpg_settings);
fmt->fmt.pix.bytesperline = 0;
fmt->fmt.pix.sizeimage =
fh->jpg_buffers.buffer_size;
fmt->fmt.pix.colorspace =
V4L2_COLORSPACE_SMPTE170M;
/* we hereby abuse this variable to show that
* we're gonna do mjpeg capture */
fh->map_mode =
(fmt->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
ZORAN_MAP_MODE_JPG_REC :
ZORAN_MAP_MODE_JPG_PLAY;
sfmtjpg_unlock_and_return:
mutex_unlock(&zr->resource_lock);
} else {
for (i = 0; i < NUM_FORMATS; i++)
if (fmt->fmt.pix.pixelformat ==
zoran_formats[i].fourcc)
break;
if (i == NUM_FORMATS) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
ZR_DEVNAME(zr),
fmt->fmt.pix.pixelformat,
(char *) &printformat);
return -EINVAL;
}
mutex_lock(&zr->resource_lock);
if (fh->jpg_buffers.allocated ||
(fh->v4l_buffers.allocated &&
fh->v4l_buffers.active !=
ZORAN_FREE)) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_FMT - cannot change capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto sfmtv4l_unlock_and_return;
}
if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
fmt->fmt.pix.height =
BUZ_MAX_HEIGHT;
if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
fmt->fmt.pix.width = BUZ_MAX_WIDTH;
if ((res =
zoran_v4l_set_format(file,
fmt->fmt.pix.
width,
fmt->fmt.pix.
height,
&zoran_formats
[i])))
goto sfmtv4l_unlock_and_return;
/* tell the user the
* results/missing stuff */
fmt->fmt.pix.bytesperline =
fh->v4l_settings.bytesperline;
fmt->fmt.pix.sizeimage =
fh->v4l_settings.height *
fh->v4l_settings.bytesperline;
fmt->fmt.pix.colorspace =
fh->v4l_settings.format->colorspace;
if (BUZ_MAX_HEIGHT <
(fh->v4l_settings.height * 2))
fmt->fmt.pix.field =
V4L2_FIELD_INTERLACED;
else
fmt->fmt.pix.field =
V4L2_FIELD_TOP;
fh->map_mode = ZORAN_MAP_MODE_RAW;
sfmtv4l_unlock_and_return:
mutex_unlock(&zr->resource_lock);
}
break; mutex_lock(&zr->resource_lock);
default: if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH)
dprintk(1, fmt->fmt.win.w.width = BUZ_MAX_WIDTH;
KERN_ERR if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH)
"%s: VIDIOC_S_FMT - unsupported type %d\n", fmt->fmt.win.w.width = BUZ_MIN_WIDTH;
ZR_DEVNAME(zr), fmt->type); if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT)
return -EINVAL; fmt->fmt.win.w.height = BUZ_MAX_HEIGHT;
} if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT)
fmt->fmt.win.w.height = BUZ_MIN_HEIGHT;
return res; mutex_unlock(&zr->resource_lock);
} return 0;
break; }
case VIDIOC_G_FBUF: static int zoran_try_fmt_vid_out(struct file *file, void *__fh,
{ struct v4l2_format *fmt)
struct v4l2_framebuffer *fb = arg; {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
struct zoran_jpg_settings settings;
int res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_FBUF\n", ZR_DEVNAME(zr)); if (fmt->fmt.pix.bytesperline > 0)
return -EINVAL;
memset(fb, 0, sizeof(*fb)); if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
mutex_lock(&zr->resource_lock); return -EINVAL;
fb->base = zr->buffer.base;
fb->fmt.width = zr->buffer.width;
fb->fmt.height = zr->buffer.height;
if (zr->overlay_settings.format) {
fb->fmt.pixelformat =
fh->overlay_settings.format->fourcc;
}
fb->fmt.bytesperline = zr->buffer.bytesperline;
mutex_unlock(&zr->resource_lock);
fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
fb->fmt.field = V4L2_FIELD_INTERLACED;
fb->flags = V4L2_FBUF_FLAG_OVERLAY;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
return 0; mutex_lock(&zr->resource_lock);
} settings = fh->jpg_settings;
break;
case VIDIOC_S_FBUF: /* we actually need to set 'real' parameters now */
{ if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT)
int i, res = 0; settings.TmpDcm = 1;
struct v4l2_framebuffer *fb = arg; else
__le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); settings.TmpDcm = 2;
settings.decimation = 0;
if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
settings.VerDcm = 2;
else
settings.VerDcm = 1;
if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
settings.HorDcm = 4;
else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
settings.HorDcm = 2;
else
settings.HorDcm = 1;
if (settings.TmpDcm == 1)
settings.field_per_buff = 2;
else
settings.field_per_buff = 1;
/* check */
res = zoran_check_jpg_settings(zr, &settings);
if (res)
goto tryfmt_unlock_and_return;
/* tell the user what we actually did */
fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
fmt->fmt.pix.height = settings.img_height * 2 /
(settings.TmpDcm * settings.VerDcm);
if (settings.TmpDcm == 1)
fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
else
fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
dprintk(3, fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings);
KERN_DEBUG tryfmt_unlock_and_return:
"%s: VIDIOC_S_FBUF - base=0x%p, size=%dx%d, bpl=%d, fmt=0x%x (%4.4s)\n", mutex_unlock(&zr->resource_lock);
ZR_DEVNAME(zr), fb->base, fb->fmt.width, fb->fmt.height, return res;
fb->fmt.bytesperline, fb->fmt.pixelformat, }
(char *) &printformat);
for (i = 0; i < NUM_FORMATS; i++) static int zoran_try_fmt_vid_cap(struct file *file, void *__fh,
if (zoran_formats[i].fourcc == fb->fmt.pixelformat) struct v4l2_format *fmt)
break; {
if (i == NUM_FORMATS) { struct zoran_fh *fh = __fh;
dprintk(1, struct zoran *zr = fh->zr;
KERN_ERR int i;
"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
ZR_DEVNAME(zr), fb->fmt.pixelformat,
(char *) &printformat);
return -EINVAL;
}
mutex_lock(&zr->resource_lock); if (fmt->fmt.pix.bytesperline > 0)
res = return -EINVAL;
setup_fbuffer(file, fb->base, &zoran_formats[i],
fb->fmt.width, fb->fmt.height,
fb->fmt.bytesperline);
mutex_unlock(&zr->resource_lock);
return res; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
} return zoran_try_fmt_vid_out(file, fh, fmt);
break;
case VIDIOC_OVERLAY: mutex_lock(&zr->resource_lock);
{
int *on = arg, res;
dprintk(3, KERN_DEBUG "%s: VIDIOC_PREVIEW - on=%d\n", for (i = 0; i < NUM_FORMATS; i++)
ZR_DEVNAME(zr), *on); if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat)
break;
mutex_lock(&zr->resource_lock); if (i == NUM_FORMATS) {
res = setup_overlay(file, *on);
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
return -EINVAL;
return res;
} }
break;
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *req = arg;
int res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_REQBUFS - type=%d\n",
ZR_DEVNAME(zr), req->type);
if (req->memory != V4L2_MEMORY_MMAP) { if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
dprintk(1, fmt->fmt.pix.width = BUZ_MAX_WIDTH;
KERN_ERR if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
"%s: only MEMORY_MMAP capture is supported, not %d\n", fmt->fmt.pix.width = BUZ_MIN_WIDTH;
ZR_DEVNAME(zr), req->memory); if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
return -EINVAL; fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
} if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
fmt->fmt.pix.height = BUZ_MIN_HEIGHT;
mutex_unlock(&zr->resource_lock);
mutex_lock(&zr->resource_lock); return 0;
}
if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) { static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh,
dprintk(1, struct v4l2_format *fmt)
KERN_ERR {
"%s: VIDIOC_REQBUFS - buffers allready allocated\n", struct zoran_fh *fh = __fh;
ZR_DEVNAME(zr)); struct zoran *zr = fh->zr;
res = -EBUSY; int res;
goto v4l2reqbuf_unlock_and_return;
} dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n",
fmt->fmt.win.w.left, fmt->fmt.win.w.top,
fmt->fmt.win.w.width,
fmt->fmt.win.w.height,
fmt->fmt.win.clipcount,
fmt->fmt.win.bitmap);
mutex_lock(&zr->resource_lock);
res = setup_window(file, fmt->fmt.win.w.left,
fmt->fmt.win.w.top,
fmt->fmt.win.w.width,
fmt->fmt.win.w.height,
(struct video_clip __user *)
fmt->fmt.win.clips,
fmt->fmt.win.clipcount,
fmt->fmt.win.bitmap);
mutex_unlock(&zr->resource_lock);
return res;
}
if (fh->map_mode == ZORAN_MAP_MODE_RAW && static int zoran_s_fmt_vid_out(struct file *file, void *__fh,
req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { struct v4l2_format *fmt)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
__le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat);
struct zoran_jpg_settings settings;
int res = 0;
/* control user input */ dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n",
if (req->count < 2) fmt->fmt.pix.width, fmt->fmt.pix.height,
req->count = 2; fmt->fmt.pix.pixelformat,
if (req->count > v4l_nbufs) (char *) &printformat);
req->count = v4l_nbufs; if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
fh->v4l_buffers.num_buffers = req->count; return -EINVAL;
if (v4l_fbuffer_alloc(file)) { mutex_lock(&zr->resource_lock);
res = -ENOMEM;
goto v4l2reqbuf_unlock_and_return;
}
/* The next mmap will map the V4L buffers */ settings = fh->jpg_settings;
fh->map_mode = ZORAN_MAP_MODE_RAW;
} else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC || if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto sfmtjpg_unlock_and_return;
}
/* we need to calculate size ourselves now */ /* we actually need to set 'real' parameters now */
if (req->count < 4) if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT)
req->count = 4; settings.TmpDcm = 1;
if (req->count > jpg_nbufs) else
req->count = jpg_nbufs; settings.TmpDcm = 2;
fh->jpg_buffers.num_buffers = req->count; settings.decimation = 0;
fh->jpg_buffers.buffer_size = if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2)
zoran_v4l2_calc_bufsize(&fh->jpg_settings); settings.VerDcm = 2;
else
if (jpg_fbuffer_alloc(file)) { settings.VerDcm = 1;
res = -ENOMEM; if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4)
goto v4l2reqbuf_unlock_and_return; settings.HorDcm = 4;
} else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2)
settings.HorDcm = 2;
/* The next mmap will map the MJPEG buffers */ else
if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) settings.HorDcm = 1;
fh->map_mode = ZORAN_MAP_MODE_JPG_REC; if (settings.TmpDcm == 1)
else settings.field_per_buff = 2;
fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY; else
settings.field_per_buff = 1;
} else {
dprintk(1, /* check */
KERN_ERR res = zoran_check_jpg_settings(zr, &settings);
"%s: VIDIOC_REQBUFS - unknown type %d\n", if (res)
ZR_DEVNAME(zr), req->type); goto sfmtjpg_unlock_and_return;
res = -EINVAL;
goto v4l2reqbuf_unlock_and_return; /* it's ok, so set them */
} fh->jpg_settings = settings;
v4l2reqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock); /* tell the user what we actually did */
fmt->fmt.pix.width = settings.img_width / settings.HorDcm;
return 0; fmt->fmt.pix.height = settings.img_height * 2 /
} (settings.TmpDcm * settings.VerDcm);
break; if (settings.TmpDcm == 1)
fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
case VIDIOC_QUERYBUF: V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT);
{ else
struct v4l2_buffer *buf = arg; fmt->fmt.pix.field = (fh->jpg_settings.odd_even ?
__u32 type = buf->type; V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM);
int index = buf->index, res; fh->jpg_buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fmt->fmt.pix.bytesperline = 0;
dprintk(3, fmt->fmt.pix.sizeimage = fh->jpg_buffers.buffer_size;
KERN_DEBUG fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
ZR_DEVNAME(zr), buf->index, buf->type); /* we hereby abuse this variable to show that
* we're gonna do mjpeg capture */
fh->map_mode = (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ?
ZORAN_MAP_MODE_JPG_REC : ZORAN_MAP_MODE_JPG_PLAY;
sfmtjpg_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
}
memset(buf, 0, sizeof(*buf)); static int zoran_s_fmt_vid_cap(struct file *file, void *__fh,
buf->type = type; struct v4l2_format *fmt)
buf->index = index; {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int i;
int res = 0;
mutex_lock(&zr->resource_lock); if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
res = zoran_v4l2_buffer_status(file, buf, buf->index); return zoran_s_fmt_vid_out(file, fh, fmt);
mutex_unlock(&zr->resource_lock);
return res; for (i = 0; i < NUM_FORMATS; i++)
if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc)
break;
if (i == NUM_FORMATS) {
dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n",
ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat);
return -EINVAL;
} }
break; mutex_lock(&zr->resource_lock);
if (fh->jpg_buffers.allocated ||
case VIDIOC_QBUF: (fh->v4l_buffers.allocated && fh->v4l_buffers.active != ZORAN_FREE)) {
{ dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n",
struct v4l2_buffer *buf = arg; ZR_DEVNAME(zr));
int res = 0, codec_mode, buf_type; res = -EBUSY;
goto sfmtv4l_unlock_and_return;
dprintk(3, }
KERN_DEBUG "%s: VIDIOC_QBUF - type=%d, index=%d\n", if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
ZR_DEVNAME(zr), buf->type, buf->index); fmt->fmt.pix.height = BUZ_MAX_HEIGHT;
if (fmt->fmt.pix.width > BUZ_MAX_WIDTH)
fmt->fmt.pix.width = BUZ_MAX_WIDTH;
res = zoran_v4l_set_format(file, fmt->fmt.pix.width,
fmt->fmt.pix.height, &zoran_formats[i]);
if (res)
goto sfmtv4l_unlock_and_return;
/* tell the user the
* results/missing stuff */
fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline;
fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline;
fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace;
if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2))
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
else
fmt->fmt.pix.field = V4L2_FIELD_TOP;
mutex_lock(&zr->resource_lock); fh->map_mode = ZORAN_MAP_MODE_RAW;
sfmtv4l_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
}
switch (fh->map_mode) { static int zoran_g_fbuf(struct file *file, void *__fh,
case ZORAN_MAP_MODE_RAW: struct v4l2_framebuffer *fb)
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { {
dprintk(1, struct zoran_fh *fh = __fh;
KERN_ERR struct zoran *zr = fh->zr;
"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
ZR_DEVNAME(zr), buf->type, fh->map_mode);
res = -EINVAL;
goto qbuf_unlock_and_return;
}
res = zoran_v4l_queue_frame(file, buf->index); memset(fb, 0, sizeof(*fb));
if (res) mutex_lock(&zr->resource_lock);
goto qbuf_unlock_and_return; fb->base = zr->buffer.base;
if (!zr->v4l_memgrab_active && fb->fmt.width = zr->buffer.width;
fh->v4l_buffers.active == ZORAN_LOCKED) fb->fmt.height = zr->buffer.height;
zr36057_set_memgrab(zr, 1); if (zr->overlay_settings.format)
break; fb->fmt.pixelformat = fh->overlay_settings.format->fourcc;
fb->fmt.bytesperline = zr->buffer.bytesperline;
mutex_unlock(&zr->resource_lock);
fb->fmt.colorspace = V4L2_COLORSPACE_SRGB;
fb->fmt.field = V4L2_FIELD_INTERLACED;
fb->flags = V4L2_FBUF_FLAG_OVERLAY;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
case ZORAN_MAP_MODE_JPG_REC: return 0;
case ZORAN_MAP_MODE_JPG_PLAY: }
if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
} else {
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
codec_mode = BUZ_MODE_MOTION_COMPRESS;
}
if (buf->type != buf_type) { static int zoran_s_fbuf(struct file *file, void *__fh,
dprintk(1, struct v4l2_framebuffer *fb)
KERN_ERR {
"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", struct zoran_fh *fh = __fh;
ZR_DEVNAME(zr), buf->type, fh->map_mode); struct zoran *zr = fh->zr;
res = -EINVAL; int i, res = 0;
goto qbuf_unlock_and_return; __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat);
}
res = for (i = 0; i < NUM_FORMATS; i++)
zoran_jpg_queue_frame(file, buf->index, if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
codec_mode);
if (res != 0)
goto qbuf_unlock_and_return;
if (zr->codec_mode == BUZ_MODE_IDLE &&
fh->jpg_buffers.active == ZORAN_LOCKED) {
zr36057_enable_jpg(zr, codec_mode);
}
break; break;
if (i == NUM_FORMATS) {
default: dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
dprintk(1, ZR_DEVNAME(zr), fb->fmt.pixelformat,
KERN_ERR (char *)&printformat);
"%s: VIDIOC_QBUF - unsupported type %d\n", return -EINVAL;
ZR_DEVNAME(zr), buf->type);
res = -EINVAL;
goto qbuf_unlock_and_return;
}
qbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
} }
break;
case VIDIOC_DQBUF:
{
struct v4l2_buffer *buf = arg;
int res = 0, buf_type, num = -1; /* compiler borks here (?) */
dprintk(3, KERN_DEBUG "%s: VIDIOC_DQBUF - type=%d\n", mutex_lock(&zr->resource_lock);
ZR_DEVNAME(zr), buf->type); res = setup_fbuffer(file, fb->base, &zoran_formats[i],
fb->fmt.width, fb->fmt.height,
mutex_lock(&zr->resource_lock); fb->fmt.bytesperline);
mutex_unlock(&zr->resource_lock);
switch (fh->map_mode) { return res;
case ZORAN_MAP_MODE_RAW: }
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
ZR_DEVNAME(zr), buf->type, fh->map_mode);
res = -EINVAL;
goto dqbuf_unlock_and_return;
}
num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; static int zoran_overlay(struct file *file, void *__fh, unsigned int on)
if (file->f_flags & O_NONBLOCK && {
zr->v4l_buffers.buffer[num].state != struct zoran_fh *fh = __fh;
BUZ_STATE_DONE) { struct zoran *zr = fh->zr;
res = -EAGAIN; int res;
goto dqbuf_unlock_and_return;
}
res = v4l_sync(file, num);
if (res)
goto dqbuf_unlock_and_return;
else
zr->v4l_sync_tail++;
res = zoran_v4l2_buffer_status(file, buf, num);
break;
case ZORAN_MAP_MODE_JPG_REC: mutex_lock(&zr->resource_lock);
case ZORAN_MAP_MODE_JPG_PLAY: res = setup_overlay(file, on);
{ mutex_unlock(&zr->resource_lock);
struct zoran_sync bs;
if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) return res;
buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; }
else
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (buf->type != buf_type) { static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req)
dprintk(1, {
KERN_ERR struct zoran_fh *fh = __fh;
"%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", struct zoran *zr = fh->zr;
ZR_DEVNAME(zr), buf->type, fh->map_mode); int res = 0;
res = -EINVAL;
goto dqbuf_unlock_and_return;
}
num = if (req->memory != V4L2_MEMORY_MMAP) {
zr->jpg_pend[zr-> dprintk(1,
jpg_que_tail & BUZ_MASK_FRAME]; KERN_ERR
"%s: only MEMORY_MMAP capture is supported, not %d\n",
ZR_DEVNAME(zr), req->memory);
return -EINVAL;
}
if (file->f_flags & O_NONBLOCK && mutex_lock(&zr->resource_lock);
zr->jpg_buffers.buffer[num].state !=
BUZ_STATE_DONE) {
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
res = jpg_sync(file, &bs);
if (res)
goto dqbuf_unlock_and_return;
res =
zoran_v4l2_buffer_status(file, buf, bs.frame);
break;
}
default: if (fh->v4l_buffers.allocated || fh->jpg_buffers.allocated) {
dprintk(1, dprintk(1,
KERN_ERR KERN_ERR
"%s: VIDIOC_DQBUF - unsupported type %d\n", "%s: VIDIOC_REQBUFS - buffers allready allocated\n",
ZR_DEVNAME(zr), buf->type); ZR_DEVNAME(zr));
res = -EINVAL; res = -EBUSY;
goto dqbuf_unlock_and_return; goto v4l2reqbuf_unlock_and_return;
}
dqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
} }
break;
case VIDIOC_STREAMON:
{
int res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMON\n", ZR_DEVNAME(zr)); if (fh->map_mode == ZORAN_MAP_MODE_RAW &&
req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
mutex_lock(&zr->resource_lock); /* control user input */
if (req->count < 2)
req->count = 2;
if (req->count > v4l_nbufs)
req->count = v4l_nbufs;
fh->v4l_buffers.num_buffers = req->count;
switch (fh->map_mode) { if (v4l_fbuffer_alloc(file)) {
case ZORAN_MAP_MODE_RAW: /* raw capture */ res = -ENOMEM;
if (zr->v4l_buffers.active != ZORAN_ACTIVE || goto v4l2reqbuf_unlock_and_return;
fh->v4l_buffers.active != ZORAN_ACTIVE) { }
res = -EBUSY;
goto strmon_unlock_and_return;
}
zr->v4l_buffers.active = fh->v4l_buffers.active = /* The next mmap will map the V4L buffers */
ZORAN_LOCKED; fh->map_mode = ZORAN_MAP_MODE_RAW;
zr->v4l_settings = fh->v4l_settings;
zr->v4l_sync_tail = zr->v4l_pend_tail; } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC ||
if (!zr->v4l_memgrab_active && fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
zr->v4l_pend_head != zr->v4l_pend_tail) {
zr36057_set_memgrab(zr, 1);
}
break;
case ZORAN_MAP_MODE_JPG_REC: /* we need to calculate size ourselves now */
case ZORAN_MAP_MODE_JPG_PLAY: if (req->count < 4)
/* what is the codec mode right now? */ req->count = 4;
if (zr->jpg_buffers.active != ZORAN_ACTIVE || if (req->count > jpg_nbufs)
fh->jpg_buffers.active != ZORAN_ACTIVE) { req->count = jpg_nbufs;
res = -EBUSY; fh->jpg_buffers.num_buffers = req->count;
goto strmon_unlock_and_return; fh->jpg_buffers.buffer_size =
} zoran_v4l2_calc_bufsize(&fh->jpg_settings);
zr->jpg_buffers.active = fh->jpg_buffers.active = if (jpg_fbuffer_alloc(file)) {
ZORAN_LOCKED; res = -ENOMEM;
goto v4l2reqbuf_unlock_and_return;
}
if (zr->jpg_que_head != zr->jpg_que_tail) { /* The next mmap will map the MJPEG buffers */
/* Start the jpeg codec when the first frame is queued */ if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
jpeg_start(zr); fh->map_mode = ZORAN_MAP_MODE_JPG_REC;
} else
fh->map_mode = ZORAN_MAP_MODE_JPG_PLAY;
break; } else {
default: dprintk(1,
dprintk(1,
KERN_ERR KERN_ERR
"%s: VIDIOC_STREAMON - invalid map mode %d\n", "%s: VIDIOC_REQBUFS - unknown type %d\n",
ZR_DEVNAME(zr), fh->map_mode); ZR_DEVNAME(zr), req->type);
res = -EINVAL; res = -EINVAL;
goto strmon_unlock_and_return; goto v4l2reqbuf_unlock_and_return;
}
strmon_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
} }
break; v4l2reqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
case VIDIOC_STREAMOFF:
{
int i, res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_STREAMOFF\n", ZR_DEVNAME(zr));
mutex_lock(&zr->resource_lock);
switch (fh->map_mode) { return res;
case ZORAN_MAP_MODE_RAW: /* raw capture */ }
if (fh->v4l_buffers.active == ZORAN_FREE &&
zr->v4l_buffers.active != ZORAN_FREE) {
res = -EPERM; /* stay off other's settings! */
goto strmoff_unlock_and_return;
}
if (zr->v4l_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
/* unload capture */ static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
if (zr->v4l_memgrab_active) { {
unsigned long flags; struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
__u32 type = buf->type;
int index = buf->index, res;
spin_lock_irqsave(&zr->spinlock, flags); memset(buf, 0, sizeof(*buf));
zr36057_set_memgrab(zr, 0); buf->type = type;
spin_unlock_irqrestore(&zr->spinlock, flags); buf->index = index;
}
for (i = 0; i < fh->v4l_buffers.num_buffers; i++) mutex_lock(&zr->resource_lock);
zr->v4l_buffers.buffer[i].state = res = zoran_v4l2_buffer_status(file, buf, buf->index);
BUZ_STATE_USER; mutex_unlock(&zr->resource_lock);
fh->v4l_buffers = zr->v4l_buffers;
zr->v4l_buffers.active = fh->v4l_buffers.active = return res;
ZORAN_FREE; }
zr->v4l_grab_seq = 0; static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
zr->v4l_pend_head = zr->v4l_pend_tail = 0; {
zr->v4l_sync_tail = 0; struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res = 0, codec_mode, buf_type;
break; mutex_lock(&zr->resource_lock);
case ZORAN_MAP_MODE_JPG_REC: switch (fh->map_mode) {
case ZORAN_MAP_MODE_JPG_PLAY: case ZORAN_MAP_MODE_RAW:
if (fh->jpg_buffers.active == ZORAN_FREE && if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
zr->jpg_buffers.active != ZORAN_FREE) { dprintk(1, KERN_ERR
res = -EPERM; /* stay off other's settings! */ "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
goto strmoff_unlock_and_return; ZR_DEVNAME(zr), buf->type, fh->map_mode);
}
if (zr->jpg_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
res =
jpg_qbuf(file, -1,
(fh->map_mode ==
ZORAN_MAP_MODE_JPG_REC) ?
BUZ_MODE_MOTION_COMPRESS :
BUZ_MODE_MOTION_DECOMPRESS);
if (res)
goto strmoff_unlock_and_return;
break;
default:
dprintk(1,
KERN_ERR
"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
ZR_DEVNAME(zr), fh->map_mode);
res = -EINVAL; res = -EINVAL;
goto strmoff_unlock_and_return; goto qbuf_unlock_and_return;
} }
strmoff_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res; res = zoran_v4l_queue_frame(file, buf->index);
} if (res)
goto qbuf_unlock_and_return;
if (!zr->v4l_memgrab_active &&
fh->v4l_buffers.active == ZORAN_LOCKED)
zr36057_set_memgrab(zr, 1);
break; break;
case VIDIOC_QUERYCTRL: case ZORAN_MAP_MODE_JPG_REC:
{ case ZORAN_MAP_MODE_JPG_PLAY:
struct v4l2_queryctrl *ctrl = arg; if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) {
buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCTRL - id=%d\n", codec_mode = BUZ_MODE_MOTION_DECOMPRESS;
ZR_DEVNAME(zr), ctrl->id); } else {
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* we only support hue/saturation/contrast/brightness */ codec_mode = BUZ_MODE_MOTION_COMPRESS;
if (ctrl->id < V4L2_CID_BRIGHTNESS ||
ctrl->id > V4L2_CID_HUE)
return -EINVAL;
else {
int id = ctrl->id;
memset(ctrl, 0, sizeof(*ctrl));
ctrl->id = id;
} }
switch (ctrl->id) { if (buf->type != buf_type) {
case V4L2_CID_BRIGHTNESS: dprintk(1, KERN_ERR
strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1); "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
break; ZR_DEVNAME(zr), buf->type, fh->map_mode);
case V4L2_CID_CONTRAST: res = -EINVAL;
strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1); goto qbuf_unlock_and_return;
break;
case V4L2_CID_SATURATION:
strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
break;
case V4L2_CID_HUE:
strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
break;
} }
ctrl->minimum = 0; res = zoran_jpg_queue_frame(file, buf->index,
ctrl->maximum = 65535; codec_mode);
ctrl->step = 1; if (res != 0)
ctrl->default_value = 32768; goto qbuf_unlock_and_return;
ctrl->type = V4L2_CTRL_TYPE_INTEGER; if (zr->codec_mode == BUZ_MODE_IDLE &&
fh->jpg_buffers.active == ZORAN_LOCKED) {
return 0; zr36057_enable_jpg(zr, codec_mode);
}
break;
case VIDIOC_G_CTRL:
{
struct v4l2_control *ctrl = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_CTRL - id=%d\n",
ZR_DEVNAME(zr), ctrl->id);
/* we only support hue/saturation/contrast/brightness */
if (ctrl->id < V4L2_CID_BRIGHTNESS ||
ctrl->id > V4L2_CID_HUE)
return -EINVAL;
mutex_lock(&zr->resource_lock);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->value = zr->brightness;
break;
case V4L2_CID_CONTRAST:
ctrl->value = zr->contrast;
break;
case V4L2_CID_SATURATION:
ctrl->value = zr->saturation;
break;
case V4L2_CID_HUE:
ctrl->value = zr->hue;
break;
} }
mutex_unlock(&zr->resource_lock); break;
return 0; default:
} dprintk(1, KERN_ERR
"%s: VIDIOC_QBUF - unsupported type %d\n",
ZR_DEVNAME(zr), buf->type);
res = -EINVAL;
break; break;
}
qbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
case VIDIOC_S_CTRL: return res;
{ }
struct v4l2_control *ctrl = arg;
struct video_picture pict;
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_CTRL - id=%d\n", static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
ZR_DEVNAME(zr), ctrl->id); {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res = 0, buf_type, num = -1; /* compiler borks here (?) */
/* we only support hue/saturation/contrast/brightness */ mutex_lock(&zr->resource_lock);
if (ctrl->id < V4L2_CID_BRIGHTNESS ||
ctrl->id > V4L2_CID_HUE)
return -EINVAL;
if (ctrl->value < 0 || ctrl->value > 65535) { switch (fh->map_mode) {
dprintk(1, case ZORAN_MAP_MODE_RAW:
KERN_ERR if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
"%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n", dprintk(1, KERN_ERR
ZR_DEVNAME(zr), ctrl->value, ctrl->id); "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
return -EINVAL; ZR_DEVNAME(zr), buf->type, fh->map_mode);
res = -EINVAL;
goto dqbuf_unlock_and_return;
} }
mutex_lock(&zr->resource_lock); num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
switch (ctrl->id) { if (file->f_flags & O_NONBLOCK &&
case V4L2_CID_BRIGHTNESS: zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) {
zr->brightness = ctrl->value; res = -EAGAIN;
break; goto dqbuf_unlock_and_return;
case V4L2_CID_CONTRAST:
zr->contrast = ctrl->value;
break;
case V4L2_CID_SATURATION:
zr->saturation = ctrl->value;
break;
case V4L2_CID_HUE:
zr->hue = ctrl->value;
break;
} }
pict.brightness = zr->brightness; res = v4l_sync(file, num);
pict.contrast = zr->contrast; if (res)
pict.colour = zr->saturation; goto dqbuf_unlock_and_return;
pict.hue = zr->hue; zr->v4l_sync_tail++;
res = zoran_v4l2_buffer_status(file, buf, num);
decoder_command(zr, DECODER_SET_PICTURE, &pict);
mutex_unlock(&zr->resource_lock);
return 0;
}
break; break;
case VIDIOC_ENUMSTD: case ZORAN_MAP_MODE_JPG_REC:
case ZORAN_MAP_MODE_JPG_PLAY:
{ {
struct v4l2_standard *std = arg; struct zoran_sync bs;
dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMSTD - index=%d\n", if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY)
ZR_DEVNAME(zr), std->index); buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
else
buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (std->index < 0 || std->index >= (zr->card.norms + 1)) if (buf->type != buf_type) {
return -EINVAL; dprintk(1, KERN_ERR
else { "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n",
int id = std->index; ZR_DEVNAME(zr), buf->type, fh->map_mode);
memset(std, 0, sizeof(*std)); res = -EINVAL;
std->index = id; goto dqbuf_unlock_and_return;
} }
if (std->index == zr->card.norms) { num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
/* if we have autodetect, ... */
struct video_decoder_capability caps;
decoder_command(zr, DECODER_GET_CAPABILITIES,
&caps);
if (caps.flags & VIDEO_DECODER_AUTO) {
std->id = V4L2_STD_ALL;
strncpy(std->name, "Autodetect", sizeof(std->name)-1);
return 0;
} else
return -EINVAL;
}
switch (std->index) {
case 0:
std->id = V4L2_STD_PAL;
strncpy(std->name, "PAL", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[0]->Ht;
break;
case 1:
std->id = V4L2_STD_NTSC;
strncpy(std->name, "NTSC", sizeof(std->name)-1);
std->frameperiod.numerator = 1001;
std->frameperiod.denominator = 30000;
std->framelines = zr->card.tvn[1]->Ht;
break;
case 2:
std->id = V4L2_STD_SECAM;
strncpy(std->name, "SECAM", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[2]->Ht;
break;
}
return 0; if (file->f_flags & O_NONBLOCK &&
zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) {
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
res = jpg_sync(file, &bs);
if (res)
goto dqbuf_unlock_and_return;
res = zoran_v4l2_buffer_status(file, buf, bs.frame);
break;
} }
default:
dprintk(1, KERN_ERR
"%s: VIDIOC_DQBUF - unsupported type %d\n",
ZR_DEVNAME(zr), buf->type);
res = -EINVAL;
break; break;
}
dqbuf_unlock_and_return:
mutex_unlock(&zr->resource_lock);
case VIDIOC_G_STD: return res;
{ }
v4l2_std_id *std = arg;
int norm;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_STD\n", ZR_DEVNAME(zr)); static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res = 0;
mutex_lock(&zr->resource_lock); mutex_lock(&zr->resource_lock);
norm = zr->norm;
mutex_unlock(&zr->resource_lock);
switch (norm) { switch (fh->map_mode) {
case VIDEO_MODE_PAL: case ZORAN_MAP_MODE_RAW: /* raw capture */
*std = V4L2_STD_PAL; if (zr->v4l_buffers.active != ZORAN_ACTIVE ||
break; fh->v4l_buffers.active != ZORAN_ACTIVE) {
case VIDEO_MODE_NTSC: res = -EBUSY;
*std = V4L2_STD_NTSC; goto strmon_unlock_and_return;
break;
case VIDEO_MODE_SECAM:
*std = V4L2_STD_SECAM;
break;
} }
return 0; zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_LOCKED;
} zr->v4l_settings = fh->v4l_settings;
zr->v4l_sync_tail = zr->v4l_pend_tail;
if (!zr->v4l_memgrab_active &&
zr->v4l_pend_head != zr->v4l_pend_tail) {
zr36057_set_memgrab(zr, 1);
}
break; break;
case VIDIOC_S_STD: case ZORAN_MAP_MODE_JPG_REC:
{ case ZORAN_MAP_MODE_JPG_PLAY:
int norm = -1, res = 0; /* what is the codec mode right now? */
v4l2_std_id *std = arg; if (zr->jpg_buffers.active != ZORAN_ACTIVE ||
fh->jpg_buffers.active != ZORAN_ACTIVE) {
res = -EBUSY;
goto strmon_unlock_and_return;
}
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n", zr->jpg_buffers.active = fh->jpg_buffers.active = ZORAN_LOCKED;
ZR_DEVNAME(zr), (unsigned long long)*std);
if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL)) if (zr->jpg_que_head != zr->jpg_que_tail) {
norm = VIDEO_MODE_PAL; /* Start the jpeg codec when the first frame is queued */
else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC)) jpeg_start(zr);
norm = VIDEO_MODE_NTSC;
else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
norm = VIDEO_MODE_SECAM;
else if (*std == V4L2_STD_ALL)
norm = VIDEO_MODE_AUTO;
else {
dprintk(1,
KERN_ERR
"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
ZR_DEVNAME(zr), (unsigned long long)*std);
return -EINVAL;
} }
break;
mutex_lock(&zr->resource_lock); default:
if ((res = zoran_set_norm(zr, norm))) dprintk(1,
goto sstd_unlock_and_return; KERN_ERR
"%s: VIDIOC_STREAMON - invalid map mode %d\n",
res = wait_grab_pending(zr); ZR_DEVNAME(zr), fh->map_mode);
sstd_unlock_and_return: res = -EINVAL;
mutex_unlock(&zr->resource_lock);
return res;
}
break; break;
}
strmon_unlock_and_return:
mutex_unlock(&zr->resource_lock);
case VIDIOC_ENUMINPUT: return res;
{ }
struct v4l2_input *inp = arg;
int status; static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int i, res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMINPUT - index=%d\n", mutex_lock(&zr->resource_lock);
ZR_DEVNAME(zr), inp->index);
if (inp->index < 0 || inp->index >= zr->card.inputs) switch (fh->map_mode) {
return -EINVAL; case ZORAN_MAP_MODE_RAW: /* raw capture */
else { if (fh->v4l_buffers.active == ZORAN_FREE &&
int id = inp->index; zr->v4l_buffers.active != ZORAN_FREE) {
memset(inp, 0, sizeof(*inp)); res = -EPERM; /* stay off other's settings! */
inp->index = id; goto strmoff_unlock_and_return;
} }
if (zr->v4l_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
strncpy(inp->name, zr->card.input[inp->index].name, /* unload capture */
sizeof(inp->name) - 1); if (zr->v4l_memgrab_active) {
inp->type = V4L2_INPUT_TYPE_CAMERA; unsigned long flags;
inp->std = V4L2_STD_ALL;
/* Get status of video decoder */
mutex_lock(&zr->resource_lock);
decoder_command(zr, DECODER_GET_STATUS, &status);
mutex_unlock(&zr->resource_lock);
if (!(status & DECODER_STATUS_GOOD)) { spin_lock_irqsave(&zr->spinlock, flags);
inp->status |= V4L2_IN_ST_NO_POWER; zr36057_set_memgrab(zr, 0);
inp->status |= V4L2_IN_ST_NO_SIGNAL; spin_unlock_irqrestore(&zr->spinlock, flags);
} }
if (!(status & DECODER_STATUS_COLOR))
inp->status |= V4L2_IN_ST_NO_COLOR;
return 0; for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
} zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER;
break; fh->v4l_buffers = zr->v4l_buffers;
case VIDIOC_G_INPUT: zr->v4l_buffers.active = fh->v4l_buffers.active = ZORAN_FREE;
{
int *input = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_INPUT\n", ZR_DEVNAME(zr)); zr->v4l_grab_seq = 0;
zr->v4l_pend_head = zr->v4l_pend_tail = 0;
zr->v4l_sync_tail = 0;
mutex_lock(&zr->resource_lock); break;
*input = zr->input;
mutex_unlock(&zr->resource_lock);
return 0; case ZORAN_MAP_MODE_JPG_REC:
} case ZORAN_MAP_MODE_JPG_PLAY:
if (fh->jpg_buffers.active == ZORAN_FREE &&
zr->jpg_buffers.active != ZORAN_FREE) {
res = -EPERM; /* stay off other's settings! */
goto strmoff_unlock_and_return;
}
if (zr->jpg_buffers.active == ZORAN_FREE)
goto strmoff_unlock_and_return;
res = jpg_qbuf(file, -1,
(fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ?
BUZ_MODE_MOTION_COMPRESS :
BUZ_MODE_MOTION_DECOMPRESS);
if (res)
goto strmoff_unlock_and_return;
break;
default:
dprintk(1, KERN_ERR
"%s: VIDIOC_STREAMOFF - invalid map mode %d\n",
ZR_DEVNAME(zr), fh->map_mode);
res = -EINVAL;
break; break;
}
strmoff_unlock_and_return:
mutex_unlock(&zr->resource_lock);
case VIDIOC_S_INPUT: return res;
{ }
int *input = arg, res = 0;
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_INPUT - input=%d\n",
ZR_DEVNAME(zr), *input);
mutex_lock(&zr->resource_lock);
if ((res = zoran_set_input(zr, *input)))
goto sinput_unlock_and_return;
/* Make sure the changes come into effect */ static int zoran_queryctrl(struct file *file, void *__fh,
res = wait_grab_pending(zr); struct v4l2_queryctrl *ctrl)
sinput_unlock_and_return: {
mutex_unlock(&zr->resource_lock); /* we only support hue/saturation/contrast/brightness */
return res; if (ctrl->id < V4L2_CID_BRIGHTNESS ||
ctrl->id > V4L2_CID_HUE)
return -EINVAL;
else {
int id = ctrl->id;
memset(ctrl, 0, sizeof(*ctrl));
ctrl->id = id;
} }
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
break;
case V4L2_CID_CONTRAST:
strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
break;
case V4L2_CID_SATURATION:
strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
break; break;
case V4L2_CID_HUE:
strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
break;
}
case VIDIOC_ENUMOUTPUT: ctrl->minimum = 0;
{ ctrl->maximum = 65535;
struct v4l2_output *outp = arg; ctrl->step = 1;
ctrl->default_value = 32768;
ctrl->type = V4L2_CTRL_TYPE_INTEGER;
dprintk(3, KERN_DEBUG "%s: VIDIOC_ENUMOUTPUT - index=%d\n", return 0;
ZR_DEVNAME(zr), outp->index); }
if (outp->index != 0) static int zoran_g_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
return -EINVAL; {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
memset(outp, 0, sizeof(*outp)); /* we only support hue/saturation/contrast/brightness */
outp->index = 0; if (ctrl->id < V4L2_CID_BRIGHTNESS ||
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; ctrl->id > V4L2_CID_HUE)
strncpy(outp->name, "Autodetect", sizeof(outp->name)-1); return -EINVAL;
return 0; mutex_lock(&zr->resource_lock);
} switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ctrl->value = zr->brightness;
break; break;
case V4L2_CID_CONTRAST:
ctrl->value = zr->contrast;
break;
case V4L2_CID_SATURATION:
ctrl->value = zr->saturation;
break;
case V4L2_CID_HUE:
ctrl->value = zr->hue;
break;
}
mutex_unlock(&zr->resource_lock);
case VIDIOC_G_OUTPUT: return 0;
{ }
int *output = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_OUTPUT\n", ZR_DEVNAME(zr)); static int zoran_s_ctrl(struct file *file, void *__fh, struct v4l2_control *ctrl)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
struct video_picture pict;
*output = 0; /* we only support hue/saturation/contrast/brightness */
if (ctrl->id < V4L2_CID_BRIGHTNESS ||
ctrl->id > V4L2_CID_HUE)
return -EINVAL;
return 0; if (ctrl->value < 0 || ctrl->value > 65535) {
dprintk(1, KERN_ERR
"%s: VIDIOC_S_CTRL - invalid value %d for id=%d\n",
ZR_DEVNAME(zr), ctrl->value, ctrl->id);
return -EINVAL;
} }
mutex_lock(&zr->resource_lock);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
zr->brightness = ctrl->value;
break;
case V4L2_CID_CONTRAST:
zr->contrast = ctrl->value;
break; break;
case V4L2_CID_SATURATION:
zr->saturation = ctrl->value;
break;
case V4L2_CID_HUE:
zr->hue = ctrl->value;
break;
}
pict.brightness = zr->brightness;
pict.contrast = zr->contrast;
pict.colour = zr->saturation;
pict.hue = zr->hue;
case VIDIOC_S_OUTPUT: decoder_command(zr, DECODER_SET_PICTURE, &pict);
{
int *output = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_S_OUTPUT - output=%d\n", mutex_unlock(&zr->resource_lock);
ZR_DEVNAME(zr), *output);
if (*output != 0) return 0;
return -EINVAL; }
return 0; static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std)
} {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int norm;
mutex_lock(&zr->resource_lock);
norm = zr->norm;
mutex_unlock(&zr->resource_lock);
switch (norm) {
case VIDEO_MODE_PAL:
*std = V4L2_STD_PAL;
break; break;
case VIDEO_MODE_NTSC:
*std = V4L2_STD_NTSC;
break;
case VIDEO_MODE_SECAM:
*std = V4L2_STD_SECAM;
break;
}
/* cropping (sub-frame capture) */ return 0;
case VIDIOC_CROPCAP: }
{
struct v4l2_cropcap *cropcap = arg;
int type = cropcap->type, res = 0;
dprintk(3, KERN_ERR "%s: VIDIOC_CROPCAP - type=%d\n", static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id *std)
ZR_DEVNAME(zr), cropcap->type); {
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int norm = -1, res = 0;
if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
norm = VIDEO_MODE_PAL;
else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
norm = VIDEO_MODE_NTSC;
else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
norm = VIDEO_MODE_SECAM;
else if (*std == V4L2_STD_ALL)
norm = VIDEO_MODE_AUTO;
else {
dprintk(1, KERN_ERR
"%s: VIDIOC_S_STD - invalid norm 0x%llx\n",
ZR_DEVNAME(zr), (unsigned long long)*std);
return -EINVAL;
}
memset(cropcap, 0, sizeof(*cropcap)); mutex_lock(&zr->resource_lock);
cropcap->type = type; res = zoran_set_norm(zr, norm);
if (res)
goto sstd_unlock_and_return;
mutex_lock(&zr->resource_lock); res = wait_grab_pending(zr);
sstd_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
}
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && static int zoran_enum_input(struct file *file, void *__fh,
(cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || struct v4l2_input *inp)
fh->map_mode == ZORAN_MAP_MODE_RAW)) { {
dprintk(1, struct zoran_fh *fh = __fh;
KERN_ERR struct zoran *zr = fh->zr;
"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n", int status;
ZR_DEVNAME(zr));
res = -EINVAL;
goto cropcap_unlock_and_return;
}
cropcap->bounds.top = cropcap->bounds.left = 0; if (inp->index < 0 || inp->index >= zr->card.inputs)
cropcap->bounds.width = BUZ_MAX_WIDTH; return -EINVAL;
cropcap->bounds.height = BUZ_MAX_HEIGHT; else {
cropcap->defrect.top = cropcap->defrect.left = 0; int id = inp->index;
cropcap->defrect.width = BUZ_MIN_WIDTH; memset(inp, 0, sizeof(*inp));
cropcap->defrect.height = BUZ_MIN_HEIGHT; inp->index = id;
cropcap_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
} }
break;
case VIDIOC_G_CROP: strncpy(inp->name, zr->card.input[inp->index].name,
{ sizeof(inp->name) - 1);
struct v4l2_crop *crop = arg; inp->type = V4L2_INPUT_TYPE_CAMERA;
int type = crop->type, res = 0; inp->std = V4L2_STD_ALL;
dprintk(3, KERN_ERR "%s: VIDIOC_G_CROP - type=%d\n", /* Get status of video decoder */
ZR_DEVNAME(zr), crop->type); mutex_lock(&zr->resource_lock);
decoder_command(zr, DECODER_GET_STATUS, &status);
mutex_unlock(&zr->resource_lock);
memset(crop, 0, sizeof(*crop)); if (!(status & DECODER_STATUS_GOOD)) {
crop->type = type; inp->status |= V4L2_IN_ST_NO_POWER;
inp->status |= V4L2_IN_ST_NO_SIGNAL;
}
if (!(status & DECODER_STATUS_COLOR))
inp->status |= V4L2_IN_ST_NO_COLOR;
mutex_lock(&zr->resource_lock); return 0;
}
if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && static int zoran_g_input(struct file *file, void *__fh, unsigned int *input)
(crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || {
fh->map_mode == ZORAN_MAP_MODE_RAW)) { struct zoran_fh *fh = __fh;
dprintk(1, struct zoran *zr = fh->zr;
KERN_ERR
"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
ZR_DEVNAME(zr));
res = -EINVAL;
goto gcrop_unlock_and_return;
}
crop->c.top = fh->jpg_settings.img_y; mutex_lock(&zr->resource_lock);
crop->c.left = fh->jpg_settings.img_x; *input = zr->input;
crop->c.width = fh->jpg_settings.img_width; mutex_unlock(&zr->resource_lock);
crop->c.height = fh->jpg_settings.img_height;
gcrop_unlock_and_return: return 0;
mutex_unlock(&zr->resource_lock); }
return res; static int zoran_s_input(struct file *file, void *__fh, unsigned int input)
} {
break; struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res;
case VIDIOC_S_CROP: mutex_lock(&zr->resource_lock);
{ res = zoran_set_input(zr, input);
struct v4l2_crop *crop = arg; if (res)
int res = 0; goto sinput_unlock_and_return;
settings = fh->jpg_settings; /* Make sure the changes come into effect */
res = wait_grab_pending(zr);
sinput_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
}
dprintk(3, static int zoran_enum_output(struct file *file, void *__fh,
KERN_ERR struct v4l2_output *outp)
"%s: VIDIOC_S_CROP - type=%d, x=%d,y=%d,w=%d,h=%d\n", {
ZR_DEVNAME(zr), crop->type, crop->c.left, crop->c.top, if (outp->index != 0)
crop->c.width, crop->c.height); return -EINVAL;
mutex_lock(&zr->resource_lock); memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) { return 0;
dprintk(1, }
KERN_ERR
"%s: VIDIOC_S_CROP - cannot change settings while active\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto scrop_unlock_and_return;
}
if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && static int zoran_g_output(struct file *file, void *__fh, unsigned int *output)
(crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || {
fh->map_mode == ZORAN_MAP_MODE_RAW)) { *output = 0;
dprintk(1,
KERN_ERR return 0;
"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n", }
ZR_DEVNAME(zr));
res = -EINVAL;
goto scrop_unlock_and_return;
}
/* move into a form that we understand */ static int zoran_s_output(struct file *file, void *__fh, unsigned int output)
settings.img_x = crop->c.left; {
settings.img_y = crop->c.top; if (output != 0)
settings.img_width = crop->c.width; return -EINVAL;
settings.img_height = crop->c.height;
/* check validity */ return 0;
if ((res = zoran_check_jpg_settings(zr, &settings))) }
goto scrop_unlock_and_return;
/* accept */ /* cropping (sub-frame capture) */
fh->jpg_settings = settings; static int zoran_cropcap(struct file *file, void *__fh,
struct v4l2_cropcap *cropcap)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int type = cropcap->type, res = 0;
scrop_unlock_and_return: memset(cropcap, 0, sizeof(*cropcap));
mutex_unlock(&zr->resource_lock); cropcap->type = type;
return res;
}
break;
case VIDIOC_G_JPEGCOMP: mutex_lock(&zr->resource_lock);
{
struct v4l2_jpegcompression *params = arg;
dprintk(3, KERN_DEBUG "%s: VIDIOC_G_JPEGCOMP\n", if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
fh->map_mode == ZORAN_MAP_MODE_RAW)) {
dprintk(1, KERN_ERR
"%s: VIDIOC_CROPCAP - subcapture only supported for compressed capture\n",
ZR_DEVNAME(zr)); ZR_DEVNAME(zr));
res = -EINVAL;
goto cropcap_unlock_and_return;
}
memset(params, 0, sizeof(*params)); cropcap->bounds.top = cropcap->bounds.left = 0;
cropcap->bounds.width = BUZ_MAX_WIDTH;
cropcap->bounds.height = BUZ_MAX_HEIGHT;
cropcap->defrect.top = cropcap->defrect.left = 0;
cropcap->defrect.width = BUZ_MIN_WIDTH;
cropcap->defrect.height = BUZ_MIN_HEIGHT;
cropcap_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res;
}
mutex_lock(&zr->resource_lock); static int zoran_g_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int type = crop->type, res = 0;
params->quality = fh->jpg_settings.jpg_comp.quality; memset(crop, 0, sizeof(*crop));
params->APPn = fh->jpg_settings.jpg_comp.APPn; crop->type = type;
memcpy(params->APP_data,
fh->jpg_settings.jpg_comp.APP_data,
fh->jpg_settings.jpg_comp.APP_len);
params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
memcpy(params->COM_data,
fh->jpg_settings.jpg_comp.COM_data,
fh->jpg_settings.jpg_comp.COM_len);
params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
params->jpeg_markers =
fh->jpg_settings.jpg_comp.jpeg_markers;
mutex_unlock(&zr->resource_lock); mutex_lock(&zr->resource_lock);
return 0; if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
fh->map_mode == ZORAN_MAP_MODE_RAW)) {
dprintk(1,
KERN_ERR
"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
ZR_DEVNAME(zr));
res = -EINVAL;
goto gcrop_unlock_and_return;
} }
break;
case VIDIOC_S_JPEGCOMP:
{
struct v4l2_jpegcompression *params = arg;
int res = 0;
settings = fh->jpg_settings; crop->c.top = fh->jpg_settings.img_y;
crop->c.left = fh->jpg_settings.img_x;
crop->c.width = fh->jpg_settings.img_width;
crop->c.height = fh->jpg_settings.img_height;
dprintk(3, gcrop_unlock_and_return:
KERN_DEBUG mutex_unlock(&zr->resource_lock);
"%s: VIDIOC_S_JPEGCOMP - quality=%d, APPN=%d, APP_len=%d, COM_len=%d\n",
ZR_DEVNAME(zr), params->quality, params->APPn,
params->APP_len, params->COM_len);
settings.jpg_comp = *params; return res;
}
mutex_lock(&zr->resource_lock); static int zoran_s_crop(struct file *file, void *__fh, struct v4l2_crop *crop)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
int res = 0;
struct zoran_jpg_settings settings;
if (fh->v4l_buffers.active != ZORAN_FREE || settings = fh->jpg_settings;
fh->jpg_buffers.active != ZORAN_FREE) {
dprintk(1,
KERN_WARNING
"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto sjpegc_unlock_and_return;
}
if ((res = zoran_check_jpg_settings(zr, &settings))) mutex_lock(&zr->resource_lock);
goto sjpegc_unlock_and_return;
if (!fh->jpg_buffers.allocated)
fh->jpg_buffers.buffer_size =
zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
sjpegc_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return 0; if (fh->jpg_buffers.allocated || fh->v4l_buffers.allocated) {
dprintk(1, KERN_ERR
"%s: VIDIOC_S_CROP - cannot change settings while active\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto scrop_unlock_and_return;
} }
break;
case VIDIOC_QUERYSTD: /* why is this useful? */ if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
{ (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
v4l2_std_id *std = arg; fh->map_mode == ZORAN_MAP_MODE_RAW)) {
dprintk(1, KERN_ERR
"%s: VIDIOC_G_CROP - subcapture only supported for compressed capture\n",
ZR_DEVNAME(zr));
res = -EINVAL;
goto scrop_unlock_and_return;
}
dprintk(3, /* move into a form that we understand */
KERN_DEBUG "%s: VIDIOC_QUERY_STD - std=0x%llx\n", settings.img_x = crop->c.left;
ZR_DEVNAME(zr), (unsigned long long)*std); settings.img_y = crop->c.top;
settings.img_width = crop->c.width;
settings.img_height = crop->c.height;
if (*std == V4L2_STD_ALL || *std == V4L2_STD_NTSC || /* check validity */
*std == V4L2_STD_PAL || (*std == V4L2_STD_SECAM && res = zoran_check_jpg_settings(zr, &settings);
zr->card.norms == 3)) { if (res)
return 0; goto scrop_unlock_and_return;
}
return -EINVAL; /* accept */
} fh->jpg_settings = settings;
break;
case VIDIOC_TRY_FMT: scrop_unlock_and_return:
{ mutex_unlock(&zr->resource_lock);
struct v4l2_format *fmt = arg; return res;
int res = 0; }
dprintk(3, KERN_DEBUG "%s: VIDIOC_TRY_FMT - type=%d\n", static int zoran_g_jpegcomp(struct file *file, void *__fh,
ZR_DEVNAME(zr), fmt->type); struct v4l2_jpegcompression *params)
{
struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
memset(params, 0, sizeof(*params));
switch (fmt->type) { mutex_lock(&zr->resource_lock);
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
mutex_lock(&zr->resource_lock);
if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH) params->quality = fh->jpg_settings.jpg_comp.quality;
fmt->fmt.win.w.width = BUZ_MAX_WIDTH; params->APPn = fh->jpg_settings.jpg_comp.APPn;
if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH) memcpy(params->APP_data,
fmt->fmt.win.w.width = BUZ_MIN_WIDTH; fh->jpg_settings.jpg_comp.APP_data,
if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT) fh->jpg_settings.jpg_comp.APP_len);
fmt->fmt.win.w.height = BUZ_MAX_HEIGHT; params->APP_len = fh->jpg_settings.jpg_comp.APP_len;
if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT) memcpy(params->COM_data,
fmt->fmt.win.w.height = BUZ_MIN_HEIGHT; fh->jpg_settings.jpg_comp.COM_data,
fh->jpg_settings.jpg_comp.COM_len);
params->COM_len = fh->jpg_settings.jpg_comp.COM_len;
params->jpeg_markers =
fh->jpg_settings.jpg_comp.jpeg_markers;
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE: return 0;
case V4L2_BUF_TYPE_VIDEO_OUTPUT: }
if (fmt->fmt.pix.bytesperline > 0)
return -EINVAL;
mutex_lock(&zr->resource_lock); static int zoran_s_jpegcomp(struct file *file, void *__fh,
struct v4l2_jpegcompression *params)
if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) { {
settings = fh->jpg_settings; struct zoran_fh *fh = __fh;
struct zoran *zr = fh->zr;
/* we actually need to set 'real' parameters now */ int res = 0;
if ((fmt->fmt.pix.height * 2) > struct zoran_jpg_settings settings;
BUZ_MAX_HEIGHT)
settings.TmpDcm = 1;
else
settings.TmpDcm = 2;
settings.decimation = 0;
if (fmt->fmt.pix.height <=
fh->jpg_settings.img_height / 2)
settings.VerDcm = 2;
else
settings.VerDcm = 1;
if (fmt->fmt.pix.width <=
fh->jpg_settings.img_width / 4)
settings.HorDcm = 4;
else if (fmt->fmt.pix.width <=
fh->jpg_settings.img_width / 2)
settings.HorDcm = 2;
else
settings.HorDcm = 1;
if (settings.TmpDcm == 1)
settings.field_per_buff = 2;
else
settings.field_per_buff = 1;
/* check */
if ((res =
zoran_check_jpg_settings(zr,
&settings)))
goto tryfmt_unlock_and_return;
/* tell the user what we actually did */
fmt->fmt.pix.width =
settings.img_width / settings.HorDcm;
fmt->fmt.pix.height =
settings.img_height * 2 /
(settings.TmpDcm * settings.VerDcm);
if (settings.TmpDcm == 1)
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_SEQ_TB :
V4L2_FIELD_SEQ_BT);
else
fmt->fmt.pix.field =
(fh->jpg_settings.
odd_even ? V4L2_FIELD_TOP :
V4L2_FIELD_BOTTOM);
fmt->fmt.pix.sizeimage =
zoran_v4l2_calc_bufsize(&settings);
} else if (fmt->type ==
V4L2_BUF_TYPE_VIDEO_CAPTURE) {
int i;
for (i = 0; i < NUM_FORMATS; i++)
if (zoran_formats[i].fourcc ==
fmt->fmt.pix.pixelformat)
break;
if (i == NUM_FORMATS) {
res = -EINVAL;
goto tryfmt_unlock_and_return;
}
if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) settings = fh->jpg_settings;
fmt->fmt.pix.width = BUZ_MAX_WIDTH;
if (fmt->fmt.pix.width < BUZ_MIN_WIDTH)
fmt->fmt.pix.width = BUZ_MIN_WIDTH;
if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT)
fmt->fmt.pix.height =
BUZ_MAX_HEIGHT;
if (fmt->fmt.pix.height < BUZ_MIN_HEIGHT)
fmt->fmt.pix.height =
BUZ_MIN_HEIGHT;
} else {
res = -EINVAL;
goto tryfmt_unlock_and_return;
}
tryfmt_unlock_and_return:
mutex_unlock(&zr->resource_lock);
return res; settings.jpg_comp = *params;
break;
default: mutex_lock(&zr->resource_lock);
return -EINVAL;
}
return 0; if (fh->v4l_buffers.active != ZORAN_FREE ||
fh->jpg_buffers.active != ZORAN_FREE) {
dprintk(1, KERN_WARNING
"%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n",
ZR_DEVNAME(zr));
res = -EBUSY;
goto sjpegc_unlock_and_return;
} }
break;
default: res = zoran_check_jpg_settings(zr, &settings);
dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n", if (res)
ZR_DEVNAME(zr), cmd); goto sjpegc_unlock_and_return;
return -ENOIOCTLCMD; if (!fh->jpg_buffers.allocated)
break; fh->jpg_buffers.buffer_size =
zoran_v4l2_calc_bufsize(&fh->jpg_settings);
fh->jpg_settings.jpg_comp = *params = settings.jpg_comp;
sjpegc_unlock_and_return:
mutex_unlock(&zr->resource_lock);
}
return 0; return 0;
} }
static long
zoran_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
return video_usercopy(file, cmd, arg, zoran_do_ioctl);
}
static unsigned int static unsigned int
zoran_poll (struct file *file, zoran_poll (struct file *file,
poll_table *wait) poll_table *wait)
...@@ -4300,10 +3933,7 @@ zoran_vm_close (struct vm_area_struct *vma) ...@@ -4300,10 +3933,7 @@ zoran_vm_close (struct vm_area_struct *vma)
fh->jpg_buffers.active = fh->jpg_buffers.active =
ZORAN_FREE; ZORAN_FREE;
} }
//jpg_fbuffer_free(file); jpg_fbuffer_free(file);
fh->jpg_buffers.allocated = 0;
fh->jpg_buffers.ready_to_be_freed = 1;
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
} }
...@@ -4340,10 +3970,7 @@ zoran_vm_close (struct vm_area_struct *vma) ...@@ -4340,10 +3970,7 @@ zoran_vm_close (struct vm_area_struct *vma)
ZORAN_FREE; ZORAN_FREE;
spin_unlock_irqrestore(&zr->spinlock, flags); spin_unlock_irqrestore(&zr->spinlock, flags);
} }
//v4l_fbuffer_free(file); v4l_fbuffer_free(file);
fh->v4l_buffers.allocated = 0;
fh->v4l_buffers.ready_to_be_freed = 1;
mutex_unlock(&zr->resource_lock); mutex_unlock(&zr->resource_lock);
} }
...@@ -4582,11 +4209,53 @@ zoran_mmap (struct file *file, ...@@ -4582,11 +4209,53 @@ zoran_mmap (struct file *file,
return 0; return 0;
} }
static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
.vidioc_querycap = zoran_querycap,
.vidioc_cropcap = zoran_cropcap,
.vidioc_s_crop = zoran_s_crop,
.vidioc_g_crop = zoran_g_crop,
.vidioc_enum_input = zoran_enum_input,
.vidioc_g_input = zoran_g_input,
.vidioc_s_input = zoran_s_input,
.vidioc_enum_output = zoran_enum_output,
.vidioc_g_output = zoran_g_output,
.vidioc_s_output = zoran_s_output,
.vidioc_g_fbuf = zoran_g_fbuf,
.vidioc_s_fbuf = zoran_s_fbuf,
.vidioc_g_std = zoran_g_std,
.vidioc_s_std = zoran_s_std,
.vidioc_g_jpegcomp = zoran_g_jpegcomp,
.vidioc_s_jpegcomp = zoran_s_jpegcomp,
.vidioc_overlay = zoran_overlay,
.vidioc_reqbufs = zoran_reqbufs,
.vidioc_querybuf = zoran_querybuf,
.vidioc_qbuf = zoran_qbuf,
.vidioc_dqbuf = zoran_dqbuf,
.vidioc_streamon = zoran_streamon,
.vidioc_streamoff = zoran_streamoff,
.vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap,
.vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out,
.vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay,
.vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap,
.vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out,
.vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay,
.vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap,
.vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out,
.vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay,
.vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap,
.vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out,
.vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay,
.vidioc_queryctrl = zoran_queryctrl,
.vidioc_s_ctrl = zoran_s_ctrl,
.vidioc_g_ctrl = zoran_g_ctrl,
.vidioc_default = zoran_default,
};
static const struct v4l2_file_operations zoran_fops = { static const struct v4l2_file_operations zoran_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = zoran_open, .open = zoran_open,
.release = zoran_close, .release = zoran_close,
.ioctl = zoran_ioctl, .ioctl = video_ioctl2,
.read = zoran_read, .read = zoran_read,
.write = zoran_write, .write = zoran_write,
.mmap = zoran_mmap, .mmap = zoran_mmap,
...@@ -4596,7 +4265,9 @@ static const struct v4l2_file_operations zoran_fops = { ...@@ -4596,7 +4265,9 @@ static const struct v4l2_file_operations zoran_fops = {
struct video_device zoran_template __devinitdata = { struct video_device zoran_template __devinitdata = {
.name = ZORAN_NAME, .name = ZORAN_NAME,
.fops = &zoran_fops, .fops = &zoran_fops,
.ioctl_ops = &zoran_ioctl_ops,
.release = &zoran_vdev_release, .release = &zoran_vdev_release,
.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
.minor = -1 .minor = -1
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment