summaryrefslogtreecommitdiff
path: root/linux/drivers/media
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-01-20 15:53:08 -0200
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-01-20 15:53:08 -0200
commitf01b6a9483f1dc1f6cb992ff34f75b2727805a8d (patch)
treef5697c12cbd352d96cd3f2b5127e972a10b99dca /linux/drivers/media
parentb8fc762c42367e93f26bba3a3eca84dec4d0fe76 (diff)
parentbe389978b07c5cb7efeb8c0d10e52b7bd236f4b7 (diff)
downloadmediapointer-dvb-s2-f01b6a9483f1dc1f6cb992ff34f75b2727805a8d.tar.gz
mediapointer-dvb-s2-f01b6a9483f1dc1f6cb992ff34f75b2727805a8d.tar.bz2
merge: http://linuxtv.org/hg/~mkrufky/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@infradead.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media')
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c891
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-risc.c171
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-vbi.c366
-rw-r--r--linux/drivers/media/video/bt8xx/bttvp.h92
-rw-r--r--linux/drivers/media/video/cpia.c8
-rw-r--r--linux/drivers/media/video/cx88/cx88-blackbird.c603
-rw-r--r--linux/drivers/media/video/cx88/cx88-core.c102
-rw-r--r--linux/drivers/media/video/cx88/cx88-vbi.c11
-rw-r--r--linux/drivers/media/video/cx88/cx88-video.c1227
-rw-r--r--linux/drivers/media/video/cx88/cx88.h48
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-audio.c46
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-context.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c5
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c25
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c4
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c5
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c19
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h17
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c260
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h13
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c16
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c42
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c34
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-io.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-std.c28
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c17
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c3
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c170
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c29
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c12
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_pas202bca.c238
-rw-r--r--linux/drivers/media/video/vivi.c1
35 files changed, 2631 insertions, 1886 deletions
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index 225c6e821..118c6e800 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -9,6 +9,10 @@
some v4l2 code lines are taken from Justin's bttv2 driver which is
(c) 2000 Justin Schoeman <justin@suntiger.ee.up.ac.za>
+ Cropping and overscan support
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems AB
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -66,6 +70,7 @@ static unsigned int radio[BTTV_MAX];
static unsigned int irq_debug;
static unsigned int gbuffers = 8;
static unsigned int gbufsize = 0x208000;
+static unsigned int reset_crop = 1;
static int video_nr = -1;
static int radio_nr = -1;
@@ -105,6 +110,7 @@ module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
module_param(gbuffers, int, 0444);
module_param(gbufsize, int, 0444);
+module_param(reset_crop, int, 0444);
module_param(v4l2, int, 0644);
module_param(bigendian, int, 0644);
@@ -140,6 +146,8 @@ MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");
MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");
MODULE_PARM_DESC(gbuffers,"number of capture buffers. range 2-32, default 8");
MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
+MODULE_PARM_DESC(reset_crop,"reset cropping parameters at open(), default "
+ "is 1 (yes) for compatibility with older applications");
MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");
MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");
MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");
@@ -205,6 +213,33 @@ static u8 SRAM_Table[][60] =
}
};
+/* minhdelayx1 first video pixel we can capture on a line and
+ hdelayx1 start of active video, both relative to rising edge of
+ /HRESET pulse (0H) in 1 / fCLKx1.
+ swidth width of active video and
+ totalwidth total line width, both in 1 / fCLKx1.
+ sqwidth total line width in square pixels.
+ vdelay start of active video in 2 * field lines relative to
+ trailing edge of /VRESET pulse (VDELAY register).
+ sheight height of active video in 2 * field lines.
+ videostart0 ITU-R frame line number of the line corresponding
+ to vdelay in the first field. */
+#define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth, \
+ vdelay, sheight, videostart0) \
+ .cropcap.bounds.left = minhdelayx1, \
+ /* * 2 because vertically we count field lines times two, */ \
+ /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */ \
+ .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
+ /* 4 is a safety margin at the end of the line. */ \
+ .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4, \
+ .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY, \
+ .cropcap.defrect.left = hdelayx1, \
+ .cropcap.defrect.top = (videostart0) * 2, \
+ .cropcap.defrect.width = swidth, \
+ .cropcap.defrect.height = sheight, \
+ .cropcap.pixelaspect.numerator = totalwidth, \
+ .cropcap.pixelaspect.denominator = sqwidth,
+
const struct bttv_tvnorm bttv_tvnorms[] = {
/* PAL-BDGHI */
/* max. active video is actually 922, but 924 is divisible by 4 and 3! */
@@ -223,11 +258,26 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 186,
.hactivex1 = 924,
.vdelay = 0x20,
- .vbipack = 255,
+ .vbipack = 255, /* min (2048 / 4, 0x1ff) & 0xff */
.sram = 0,
/* ITU-R frame line number of the first VBI line
- we can capture, of the first and second field. */
- .vbistart = { 7,320 },
+ we can capture, of the first and second field.
+ The last line is determined by cropcap.bounds. */
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* Should be (768 * 1135 + 944 / 2) / 944.
+ cropcap.defrect is used for image width
+ checks, so we keep the old value 924. */
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
+ /* bt878 (and bt848?) can capture another
+ line below active video. */
+ .cropcap.bounds.height = (576 + 2) + 0x20 - 2,
},{
.v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
.name = "NTSC",
@@ -242,9 +292,18 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.hdelayx1 = 128,
.hactivex1 = 910,
.vdelay = 0x1a,
- .vbipack = 144,
+ .vbipack = 144, /* min (1600 / 4, 0x1ff) & 0xff */
.sram = 1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 128,
+ /* Should be (640 * 910 + 780 / 2) / 780? */
+ /* swidth */ 768,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_SECAM,
.name = "SECAM",
@@ -262,6 +321,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 255,
.sram = 0, /* like PAL, correct? */
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_Nc,
.name = "PAL-Nc",
@@ -279,6 +346,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 130,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_M,
.name = "PAL-M",
@@ -296,6 +371,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vbipack = 144,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_PAL_N,
.name = "PAL-N",
@@ -312,7 +395,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x20,
.vbipack = 144,
.sram = -1,
- .vbistart = { 7, 320},
+ .vbistart = { 7, 320 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ (768 * 1135 + 944 / 2) / 944,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x20,
+ /* sheight */ 576,
+ /* videostart0 */ 23)
},{
.v4l2_id = V4L2_STD_NTSC_M_JP,
.name = "NTSC-JP",
@@ -329,7 +420,15 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vdelay = 0x16,
.vbipack = 144,
.sram = -1,
- .vbistart = {10, 273},
+ .vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 135,
+ /* swidth */ (640 * 910 + 780 / 2) / 780,
+ /* totalwidth */ 910,
+ /* sqwidth */ 780,
+ /* vdelay */ 0x16,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
},{
/* that one hopefully works with the strange timing
* which video recorders produce when playing a NTSC
@@ -351,6 +450,14 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
.vtotal = 524,
.sram = -1,
.vbistart = { 10, 273 },
+ CROPCAP(/* minhdelayx1 */ 68,
+ /* hdelayx1 */ 186,
+ /* swidth */ 924,
+ /* totalwidth */ 1135,
+ /* sqwidth */ 944,
+ /* vdelay */ 0x1a,
+ /* sheight */ 480,
+ /* videostart0 */ 23)
}
};
static const unsigned int BTTV_TVNORMS = ARRAY_SIZE(bttv_tvnorms);
@@ -691,25 +798,89 @@ static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
/* ----------------------------------------------------------------------- */
/* resource management */
+/*
+ RESOURCE_ allocated by freed by
+
+ VIDEO_READ bttv_read 1) bttv_read 2)
+
+ VIDEO_STREAM VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ VIDIOCMCAPTURE 1)
+
+ OVERLAY VIDIOCCAPTURE on VIDIOCCAPTURE off
+ VIDIOC_OVERLAY on VIDIOC_OVERLAY off
+ 3) bttv_release
+
+ VBI VIDIOC_STREAMON VIDIOC_STREAMOFF
+ VIDIOC_QBUF 1) bttv_release
+ bttv_read, bttv_poll 1) 4)
+
+ 1) The resource must be allocated when we enter buffer prepare functions
+ and remain allocated while buffers are in the DMA queue.
+ 2) This is a single frame read.
+ 3) VIDIOC_S_FBUF and VIDIOC_S_FMT (OVERLAY) still work when
+ RESOURCE_OVERLAY is allocated.
+ 4) This is a continuous read, implies VIDIOC_STREAMON.
+
+ Note this driver permits video input and standard changes regardless if
+ resources are allocated.
+*/
+
+#define VBI_RESOURCES (RESOURCE_VBI)
+#define VIDEO_RESOURCES (RESOURCE_VIDEO_READ | \
+ RESOURCE_VIDEO_STREAM | \
+ RESOURCE_OVERLAY)
+
static
int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
{
+ int xbits; /* mutual exclusive resources */
+
if (fh->resources & bit)
/* have it already allocated */
return 1;
+ xbits = bit;
+ if (bit & (RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM))
+ xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
+
/* is it free? */
- mutex_lock(&btv->reslock);
- if (btv->resources & bit) {
+ mutex_lock(&btv->lock);
+ if (btv->resources & xbits) {
/* no, someone else uses it */
- mutex_unlock(&btv->reslock);
- return 0;
+ goto fail;
+ }
+
+ if ((bit & VIDEO_RESOURCES)
+ && 0 == (btv->resources & VIDEO_RESOURCES)) {
+ /* Do crop - use current, don't - use default parameters. */
+ __s32 top = btv->crop[!!fh->do_crop].rect.top;
+
+ if (btv->vbi_end > top)
+ goto fail;
+
+ /* We cannot capture the same line as video and VBI data.
+ Claim scan lines crop[].rect.top to bottom. */
+ btv->crop_start = top;
+ } else if (bit & VBI_RESOURCES) {
+ __s32 end = fh->vbi_fmt.end;
+
+ if (end > btv->crop_start)
+ goto fail;
+
+ /* Claim scan lines above fh->vbi_fmt.end. */
+ btv->vbi_end = end;
}
+
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->reslock);
+ mutex_unlock(&btv->lock);
return 1;
+
+ fail:
+ mutex_unlock(&btv->lock);
+ return 0;
}
static
@@ -724,6 +895,35 @@ int locked_btres(struct bttv *btv, int bit)
return (btv->resources & bit);
}
+/* Call with btv->lock down. */
+static void
+disclaim_vbi_lines(struct bttv *btv)
+{
+ btv->vbi_end = 0;
+}
+
+/* Call with btv->lock down. */
+static void
+disclaim_video_lines(struct bttv *btv)
+{
+ const struct bttv_tvnorm *tvnorm;
+ u8 crop;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+
+ /* VBI capturing ends at VDELAY, start of video capturing, no
+ matter how many lines the VBI RISC program expects. When video
+ capturing is off, it shall no longer "preempt" VBI capturing,
+ so we set VDELAY to maximum. */
+ crop = btread(BT848_E_CROP) | 0xc0;
+ btwrite(crop, BT848_E_CROP);
+ btwrite(0xfe, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ btwrite(0xfe, BT848_O_VDELAY_LO);
+}
+
static
void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
{
@@ -733,10 +933,19 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
printk("bttv: BUG! (btres)\n");
}
#endif
- mutex_lock(&btv->reslock);
+ mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
- mutex_unlock(&btv->reslock);
+
+ bits = btv->resources;
+
+ if (0 == (bits & VIDEO_RESOURCES))
+ disclaim_video_lines(btv);
+
+ if (0 == (bits & VBI_RESOURCES))
+ disclaim_vbi_lines(btv);
+
+ mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
@@ -1050,6 +1259,36 @@ i2c_vidiocschan(struct bttv *btv)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
+static void
+bttv_crop_calc_limits(struct bttv_crop *c)
+{
+ /* Scale factor min. 1:1, max. 16:1. Min. image size
+ 48 x 32. Scaled width must be a multiple of 4. */
+
+ if (1) {
+ /* For bug compatibility with VIDIOCGCAP and image
+ size checks in earlier driver versions. */
+ c->min_scaled_width = 48;
+ c->min_scaled_height = 32;
+ } else {
+ c->min_scaled_width =
+ (max(48, c->rect.width >> 4) + 3) & ~3;
+ c->min_scaled_height =
+ max(32, c->rect.height >> 4);
+ }
+
+ c->max_scaled_width = c->rect.width & ~3;
+ c->max_scaled_height = c->rect.height;
+}
+
+static void
+bttv_crop_reset(struct bttv_crop *c, int norm)
+{
+ c->rect = bttv_tvnorms[norm].cropcap.defrect;
+ bttv_crop_calc_limits(c);
+}
+
+/* Call with btv->lock down. */
static int
set_tvnorm(struct bttv *btv, unsigned int norm)
{
@@ -1058,9 +1297,24 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
if (norm < 0 || norm >= BTTV_TVNORMS)
return -EINVAL;
- btv->tvnorm = norm;
tvnorm = &bttv_tvnorms[norm];
+ if (btv->tvnorm < 0 ||
+ btv->tvnorm >= BTTV_TVNORMS ||
+ 0 != memcmp(&bttv_tvnorms[btv->tvnorm].cropcap,
+ &tvnorm->cropcap,
+ sizeof (tvnorm->cropcap))) {
+ bttv_crop_reset(&btv->crop[0], norm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+
+ if (0 == (btv->resources & VIDEO_RESOURCES)) {
+ btv->crop_start = tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height;
+ }
+ }
+
+ btv->tvnorm = norm;
+
btwrite(tvnorm->adelay, BT848_ADELAY);
btwrite(tvnorm->bdelay, BT848_BDELAY);
btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH),
@@ -1082,6 +1336,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
return 0;
}
+/* Call with btv->lock down. */
static void
set_input(struct bttv *btv, unsigned int input)
{
@@ -1484,13 +1739,13 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
btv->loop_irq |= 1;
bttv_set_dma(btv, 0x03);
spin_unlock_irqrestore(&btv->s_lock,flags);
- if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
if (NULL != old) {
dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state);
bttv_dma_free(&fh->cap,btv, old);
kfree(old);
}
+ if (NULL == new)
+ free_btres(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
return retval;
}
@@ -1504,7 +1759,10 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
unsigned int width, unsigned int height,
enum v4l2_field field)
{
+ struct bttv_fh *fh = q->priv_data;
int redo_dma_risc = 0;
+ struct bttv_crop c;
+ int norm;
int rc;
/* check settings */
@@ -1516,12 +1774,52 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
if (width*height > buf->vb.bsize)
return -EINVAL;
buf->vb.size = buf->vb.bsize;
+
+ /* Make sure tvnorm and vbi_end remain consistent
+ until we're done. */
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+
+ /* In this mode capturing always starts at defrect.top
+ (default VDELAY), ignoring cropping parameters. */
+ if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
+ mutex_unlock(&btv->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&btv->lock);
+
+ c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- if (width < 48 ||
- height < 32 ||
- width > bttv_tvnorms[btv->tvnorm].swidth ||
- height > bttv_tvnorms[btv->tvnorm].sheight)
+ mutex_lock(&btv->lock);
+
+ norm = btv->tvnorm;
+ c = btv->crop[!!fh->do_crop];
+
+ mutex_unlock(&btv->lock);
+
+ if (width < c.min_scaled_width ||
+ width > c.max_scaled_width ||
+ height < c.min_scaled_height)
return -EINVAL;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_ALTERNATE:
+ /* btv->crop counts frame lines. Max. scale
+ factor is 16:1 for frames, 8:1 for fields. */
+ if (height * 2 > c.max_scaled_height)
+ return -EINVAL;
+ break;
+
+ default:
+ if (height > c.max_scaled_height)
+ return -EINVAL;
+ break;
+ }
+
buf->vb.size = (width * height * fmt->depth) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -1530,12 +1828,17 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
/* alloc + fill struct bttv_buffer (if changed) */
if (buf->vb.width != width || buf->vb.height != height ||
buf->vb.field != field ||
- buf->tvnorm != btv->tvnorm || buf->fmt != fmt) {
+ buf->tvnorm != norm || buf->fmt != fmt ||
+ buf->crop.top != c.rect.top ||
+ buf->crop.left != c.rect.left ||
+ buf->crop.width != c.rect.width ||
+ buf->crop.height != c.rect.height) {
buf->vb.width = width;
buf->vb.height = height;
buf->vb.field = field;
- buf->tvnorm = btv->tvnorm;
+ buf->tvnorm = norm;
buf->fmt = fmt;
+ buf->crop = c.rect;
redo_dma_risc = 1;
}
@@ -1964,11 +2267,179 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
return 0;
}
-static int verify_window(const struct bttv_tvnorm *tvn,
- struct v4l2_window *win, int fixup)
+/* Given cropping boundaries b and the scaled width and height of a
+ single field or frame, which must not exceed hardware limits, this
+ function adjusts the cropping parameters c. */
+static void
+bttv_crop_adjust (struct bttv_crop * c,
+ const struct v4l2_rect * b,
+ __s32 width,
+ __s32 height,
+ enum v4l2_field field)
+{
+ __s32 frame_height = height << !V4L2_FIELD_HAS_BOTH(field);
+ __s32 max_left;
+ __s32 max_top;
+
+ if (width < c->min_scaled_width) {
+ /* Max. hor. scale factor 16:1. */
+ c->rect.width = width * 16;
+ } else if (width > c->max_scaled_width) {
+ /* Min. hor. scale factor 1:1. */
+ c->rect.width = width;
+
+ max_left = b->left + b->width - width;
+ max_left = min(max_left, (__s32) MAX_HDELAY);
+ if (c->rect.left > max_left)
+ c->rect.left = max_left;
+ }
+
+ if (height < c->min_scaled_height) {
+ /* Max. vert. scale factor 16:1, single fields 8:1. */
+ c->rect.height = height * 16;
+ } else if (frame_height > c->max_scaled_height) {
+ /* Min. vert. scale factor 1:1.
+ Top and height count field lines times two. */
+ c->rect.height = (frame_height + 1) & ~1;
+
+ max_top = b->top + b->height - c->rect.height;
+ if (c->rect.top > max_top)
+ c->rect.top = max_top;
+ }
+
+ bttv_crop_calc_limits(c);
+}
+
+/* Returns an error if scaling to a frame or single field with the given
+ width and height is not possible with the current cropping parameters
+ and width aligned according to width_mask. If adjust_size is TRUE the
+ function may adjust the width and/or height instead, rounding width
+ to (width + width_bias) & width_mask. If adjust_crop is TRUE it may
+ also adjust the current cropping parameters to get closer to the
+ desired image size. */
+static int
+limit_scaled_size (struct bttv_fh * fh,
+ __s32 * width,
+ __s32 * height,
+ enum v4l2_field field,
+ unsigned int width_mask,
+ unsigned int width_bias,
+ int adjust_size,
+ int adjust_crop)
+{
+ struct bttv *btv = fh->btv;
+ const struct v4l2_rect *b;
+ struct bttv_crop *c;
+ __s32 min_width;
+ __s32 min_height;
+ __s32 max_width;
+ __s32 max_height;
+ int rc;
+
+ BUG_ON((int) width_mask >= 0 ||
+ width_bias >= (unsigned int) -width_mask);
+
+ /* Make sure tvnorm, vbi_end and the current cropping parameters
+ remain consistent until we're done. */
+ mutex_lock(&btv->lock);
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ /* Do crop - use current, don't - use default parameters. */
+ c = &btv->crop[!!fh->do_crop];
+
+ if (fh->do_crop
+ && adjust_size
+ && adjust_crop
+ && !locked_btres(btv, VIDEO_RESOURCES)) {
+ min_width = 48;
+ min_height = 32;
+
+ /* We cannot scale up. When the scaled image is larger
+ than crop.rect we adjust the crop.rect as required
+ by the V4L2 spec, hence cropcap.bounds are our limit. */
+ max_width = min(b->width, (__s32) MAX_HACTIVE);
+ max_height = b->height;
+
+ /* We cannot capture the same line as video and VBI data.
+ Note btv->vbi_end is really a minimum, see
+ bttv_vbi_try_fmt(). */
+ if (btv->vbi_end > b->top) {
+ max_height -= btv->vbi_end - b->top;
+ rc = -EBUSY;
+ if (min_height > max_height)
+ goto fail;
+ }
+ } else {
+ rc = -EBUSY;
+ if (btv->vbi_end > c->rect.top)
+ goto fail;
+
+ min_width = c->min_scaled_width;
+ min_height = c->min_scaled_height;
+ max_width = c->max_scaled_width;
+ max_height = c->max_scaled_height;
+
+ adjust_crop = 0;
+ }
+
+ min_width = (min_width - width_mask - 1) & width_mask;
+ max_width = max_width & width_mask;
+
+ /* Max. scale factor is 16:1 for frames, 8:1 for fields. */
+ min_height = min_height;
+ /* Min. scale factor is 1:1. */
+ max_height >>= !V4L2_FIELD_HAS_BOTH(field);
+
+ if (adjust_size) {
+ *width = clamp(*width, min_width, max_width);
+ *height = clamp(*height, min_height, max_height);
+
+ /* Round after clamping to avoid overflow. */
+ *width = (*width + width_bias) & width_mask;
+
+ if (adjust_crop) {
+ bttv_crop_adjust(c, b, *width, *height, field);
+
+ if (btv->vbi_end > c->rect.top) {
+ /* Move the crop window out of the way. */
+ c->rect.top = btv->vbi_end;
+ }
+ }
+ } else {
+ rc = -EINVAL;
+ if (*width < min_width ||
+ *height < min_height ||
+ *width > max_width ||
+ *height > max_height ||
+ 0 != (*width & ~width_mask))
+ goto fail;
+ }
+
+ rc = 0; /* success */
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+/* Returns an error if the given overlay window dimensions are not
+ possible with the current cropping parameters. If adjust_size is
+ TRUE the function may adjust the window width and/or height
+ instead, however it always rounds the horizontal position and
+ width as btcx_align() does. If adjust_crop is TRUE the function
+ may also adjust the current cropping parameters to get closer
+ to the desired window size. */
+static int
+verify_window (struct bttv_fh * fh,
+ struct v4l2_window * win,
+ int adjust_size,
+ int adjust_crop)
{
enum v4l2_field field;
- int maxw, maxh;
+ unsigned int width_mask;
+ int rc;
if (win->w.width < 48 || win->w.height < 32)
return -EINVAL;
@@ -1976,32 +2447,52 @@ static int verify_window(const struct bttv_tvnorm *tvn,
return -EINVAL;
field = win->field;
- maxw = tvn->swidth;
- maxh = tvn->sheight;
if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
+ __s32 height2;
+
+ height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
}
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
case V4L2_FIELD_INTERLACED:
break;
default:
return -EINVAL;
}
- if (!fixup && (win->w.width > maxw || win->w.height > maxh))
+ /* 4-byte alignment. */
+ if (NULL == fh->ovfmt)
return -EINVAL;
+ width_mask = ~0;
+ switch (fh->ovfmt->depth) {
+ case 8:
+ case 24:
+ width_mask = ~3;
+ break;
+ case 16:
+ width_mask = ~1;
+ break;
+ case 32:
+ break;
+ default:
+ BUG();
+ }
+
+ win->w.width -= win->w.left & ~width_mask;
+ win->w.left = (win->w.left - width_mask - 1) & width_mask;
+
+ rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+ field, width_mask,
+ /* width_bias: round down */ 0,
+ adjust_size, adjust_crop);
+ if (0 != rc)
+ return rc;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
win->field = field;
return 0;
}
@@ -2016,7 +2507,9 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- retval = verify_window(&bttv_tvnorms[btv->tvnorm],win,fixup);
+ retval = verify_window(fh, win,
+ /* adjust_size */ fixup,
+ /* adjust_crop */ fixup);
if (0 != retval)
return retval;
@@ -2073,6 +2566,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2105,7 +2599,7 @@ static int bttv_resource(struct bttv_fh *fh)
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- res = RESOURCE_VIDEO;
+ res = RESOURCE_VIDEO_STREAM;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
res = RESOURCE_VBI;
@@ -2163,7 +2657,7 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
f->fmt.win.field = fh->ov.field;
return 0;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_get_fmt(fh,f);
+ bttv_vbi_get_fmt(fh, &f->fmt.vbi);
return 0;
default:
return -EINVAL;
@@ -2171,35 +2665,35 @@ static int bttv_g_fmt(struct bttv_fh *fh, struct v4l2_format *f)
}
static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
- struct v4l2_format *f)
+ struct v4l2_format *f, int adjust_crop)
{
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
{
const struct bttv_format *fmt;
enum v4l2_field field;
- unsigned int maxw,maxh;
+ __s32 width, height;
+ int rc;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
- /* fixup format */
- maxw = bttv_tvnorms[btv->tvnorm].swidth;
- maxh = bttv_tvnorms[btv->tvnorm].sheight;
field = f->fmt.pix.field;
- if (V4L2_FIELD_ANY == field)
- field = (f->fmt.pix.height > maxh/2)
+ if (V4L2_FIELD_ANY == field) {
+ __s32 height2;
+
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
+ }
if (V4L2_FIELD_SEQ_BT == field)
field = V4L2_FIELD_SEQ_TB;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_ALTERNATE:
- maxh = maxh/2;
- break;
case V4L2_FIELD_INTERLACED:
break;
case V4L2_FIELD_SEQ_TB:
@@ -2210,28 +2704,29 @@ static int bttv_try_fmt(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
}
+ width = f->fmt.pix.width;
+ height = f->fmt.pix.height;
+
+ rc = limit_scaled_size(fh, &width, &height, field,
+ /* width_mask: 4 pixels */ ~3,
+ /* width_bias: nearest */ 2,
+ /* adjust_size */ 1,
+ adjust_crop);
+ if (0 != rc)
+ return rc;
+
/* update data for the application */
f->fmt.pix.field = field;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- pix_format_set_size (&f->fmt.pix, fmt,
- f->fmt.pix.width & ~3,
- f->fmt.pix.height);
+ pix_format_set_size(&f->fmt.pix, fmt, width, height);
return 0;
}
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- return verify_window(&bttv_tvnorms[btv->tvnorm],
- &f->fmt.win, 1);
+ return verify_window(fh, &f->fmt.win,
+ /* adjust_size */ 1,
+ /* adjust_crop */ 0);
case V4L2_BUF_TYPE_VBI_CAPTURE:
- bttv_vbi_try_fmt(fh,f);
- return 0;
+ return bttv_vbi_try_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2250,7 +2745,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- retval = bttv_try_fmt(fh,btv,f);
+ retval = bttv_try_fmt(fh,btv,f, /* adjust_crop */ 1);
if (0 != retval)
return retval;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -2279,12 +2774,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv,
retval = bttv_switch_type(fh,f->type);
if (0 != retval)
return retval;
- if (locked_btres(fh->btv, RESOURCE_VBI))
- return -EBUSY;
- bttv_vbi_try_fmt(fh,f);
- bttv_vbi_setlines(fh,btv,f->fmt.vbi.count[0]);
- bttv_vbi_get_fmt(fh,f);
- return 0;
+ return bttv_vbi_set_fmt(fh, &f->fmt.vbi);
default:
return -EINVAL;
}
@@ -2542,6 +3032,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (*on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
new = NULL;
@@ -2576,10 +3067,16 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct video_mmap *vm = arg;
struct bttv_buffer *buf;
enum v4l2_field field;
+ __s32 height2;
+ int res;
if (vm->frame >= VIDEO_MAX_FRAME)
return -EINVAL;
+ res = bttv_resource(fh);
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
+
mutex_lock(&fh->cap.lock);
retval = -EINVAL;
buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame];
@@ -2591,7 +3088,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
buf->vb.state == STATE_ACTIVE)
goto fh_unlock_and_return;
- field = (vm->height > bttv_tvnorms[btv->tvnorm].sheight/2)
+ height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ field = (vm->height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
retval = bttv_prepare_buffer(&fh->cap,btv,buf,
@@ -2638,54 +3136,17 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
}
case VIDIOCGVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
-
if (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE) {
retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
if (0 != retval)
return retval;
}
- bttv_vbi_get_fmt(fh, &fmt2);
-
- memset(fmt,0,sizeof(*fmt));
- fmt->sampling_rate = fmt2.fmt.vbi.sampling_rate;
- fmt->samples_per_line = fmt2.fmt.vbi.samples_per_line;
- fmt->sample_format = VIDEO_PALETTE_RAW;
- fmt->start[0] = fmt2.fmt.vbi.start[0];
- fmt->count[0] = fmt2.fmt.vbi.count[0];
- fmt->start[1] = fmt2.fmt.vbi.start[1];
- fmt->count[1] = fmt2.fmt.vbi.count[1];
- if (fmt2.fmt.vbi.flags & V4L2_VBI_UNSYNC)
- fmt->flags |= VBI_UNSYNC;
- if (fmt2.fmt.vbi.flags & V4L2_VBI_INTERLACED)
- fmt->flags |= VBI_INTERLACED;
- return 0;
- }
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *fmt = (void *) arg;
- struct v4l2_format fmt2;
- retval = bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- if (0 != retval)
- return retval;
- bttv_vbi_get_fmt(fh, &fmt2);
-
- if (fmt->sampling_rate != fmt2.fmt.vbi.sampling_rate ||
- fmt->samples_per_line != fmt2.fmt.vbi.samples_per_line ||
- fmt->sample_format != VIDEO_PALETTE_RAW ||
- fmt->start[0] != fmt2.fmt.vbi.start[0] ||
- fmt->start[1] != fmt2.fmt.vbi.start[1] ||
- fmt->count[0] != fmt->count[1] ||
- fmt->count[0] < 1 ||
- fmt->count[0] > 32 /* VBI_MAXLINES */)
- return -EINVAL;
+ /* fall through */
- bttv_vbi_setlines(fh,btv,fmt->count[0]);
- return 0;
- }
+ case VIDIOCSVBIFMT:
+ return v4l_compat_translate_ioctl(inode, file, cmd,
+ arg, bttv_do_ioctl);
case BTTV_VERSION:
case VIDIOCGFREQ:
@@ -2778,7 +3239,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_TRY_FMT:
{
struct v4l2_format *f = arg;
- return bttv_try_fmt(fh,btv,f);
+ return bttv_try_fmt(fh,btv,f, /* adjust_crop */ 0);
}
case VIDIOC_G_FMT:
{
@@ -2817,16 +3278,23 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
if (0 == (fmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- mutex_lock(&fh->cap.lock);
retval = -EINVAL;
if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) {
- if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth)
- goto fh_unlock_and_return;
- if (fb->fmt.height > bttv_tvnorms[btv->tvnorm].sheight)
- goto fh_unlock_and_return;
+ __s32 width = fb->fmt.width;
+ __s32 height = fb->fmt.height;
+
+ retval = limit_scaled_size(fh, &width, &height,
+ V4L2_FIELD_INTERLACED,
+ /* width_mask */ ~3,
+ /* width_bias */ 2,
+ /* adjust_size */ 0,
+ /* adjust_crop */ 0);
+ if (0 != retval)
+ return retval;
}
/* ok, accept it */
+ mutex_lock(&fh->cap.lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2853,6 +3321,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
struct bttv_buffer *new;
new = videobuf_alloc(sizeof(*new));
+ new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
retval = bttv_switch_overlay(btv,fh,new);
}
@@ -2868,7 +3337,13 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return videobuf_querybuf(bttv_queue(fh),arg);
case VIDIOC_QBUF:
+ {
+ int res = bttv_resource(fh);
+
+ if (!check_alloc_btres(btv, fh, res))
+ return -EBUSY;
return videobuf_qbuf(bttv_queue(fh),arg);
+ }
case VIDIOC_DQBUF:
return videobuf_dqbuf(bttv_queue(fh),arg,
@@ -2967,6 +3442,122 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
return v4l2_prio_change(&btv->prio, &fh->prio, *prio);
}
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *cap = arg;
+ enum v4l2_buf_type type;
+
+ type = cap->type;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ *cap = bttv_tvnorms[btv->tvnorm].cropcap;
+ cap->type = type;
+
+ return 0;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop * crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ /* No fh->do_crop = 1; because btv->crop[1] may be
+ inconsistent with fh->width or fh->height and apps
+ do not expect a change here. */
+
+ crop->c = btv->crop[!!fh->do_crop].rect;
+
+ return 0;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *crop = arg;
+ const struct v4l2_rect *b;
+ struct bttv_crop c;
+ __s32 b_left;
+ __s32 b_top;
+ __s32 b_right;
+ __s32 b_bottom;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
+ return -EINVAL;
+
+ retval = v4l2_prio_check(&btv->prio,&fh->prio);
+ if (0 != retval)
+ return retval;
+
+ /* Make sure tvnorm, vbi_end and the current cropping
+ parameters remain consistent until we're done. Note
+ read() may change vbi_end in check_alloc_btres(). */
+ mutex_lock(&btv->lock);
+
+ retval = -EBUSY;
+
+ if (locked_btres(fh->btv, VIDEO_RESOURCES))
+ goto btv_unlock_and_return;
+
+ b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
+
+ b_left = b->left;
+ b_right = b_left + b->width;
+ b_bottom = b->top + b->height;
+
+ b_top = max(b->top, btv->vbi_end);
+ if (b_top + 32 >= b_bottom)
+ goto btv_unlock_and_return;
+
+ /* Min. scaled size 48 x 32. */
+ c.rect.left = clamp(crop->c.left, b_left, b_right - 48);
+ c.rect.left = min(c.rect.left, (__s32) MAX_HDELAY);
+
+ c.rect.width = clamp(crop->c.width,
+ 48, b_right - c.rect.left);
+
+ c.rect.top = clamp(crop->c.top, b_top, b_bottom - 32);
+ /* Top and height must be a multiple of two. */
+ c.rect.top = (c.rect.top + 1) & ~1;
+
+ c.rect.height = clamp(crop->c.height,
+ 32, b_bottom - c.rect.top);
+ c.rect.height = (c.rect.height + 1) & ~1;
+
+ bttv_crop_calc_limits(&c);
+
+ btv->crop[1] = c;
+
+ mutex_unlock(&btv->lock);
+
+ fh->do_crop = 1;
+
+ mutex_lock(&fh->cap.lock);
+
+ if (fh->width < c.min_scaled_width) {
+ fh->width = c.min_scaled_width;
+ btv->init.width = c.min_scaled_width;
+ } else if (fh->width > c.max_scaled_width) {
+ fh->width = c.max_scaled_width;
+ btv->init.width = c.max_scaled_width;
+ }
+
+ if (fh->height < c.min_scaled_height) {
+ fh->height = c.min_scaled_height;
+ btv->init.height = c.min_scaled_height;
+ } else if (fh->height > c.max_scaled_height) {
+ fh->height = c.max_scaled_height;
+ btv->init.height = c.max_scaled_height;
+ }
+
+ mutex_unlock(&fh->cap.lock);
+
+ return 0;
+ }
+
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
@@ -2988,6 +3579,10 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fh_unlock_and_return:
mutex_unlock(&fh->cap.lock);
return retval;
+
+ btv_unlock_and_return:
+ mutex_unlock(&btv->lock);
+ return retval;
}
static int bttv_ioctl(struct inode *inode, struct file *file,
@@ -2997,8 +3592,26 @@ static int bttv_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case BTTV_VBISIZE:
+ {
+ const struct bttv_tvnorm *tvnorm;
+
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ if (fh->vbi_fmt.fmt.start[0] != tvnorm->vbistart[0] ||
+ fh->vbi_fmt.fmt.start[1] != tvnorm->vbistart[1] ||
+ fh->vbi_fmt.fmt.count[0] != fh->vbi_fmt.fmt.count[1]) {
+ /* BTTV_VBISIZE cannot express these parameters,
+ however open() resets the paramters to defaults
+ and apps shouldn't call BTTV_VBISIZE after
+ VIDIOC_S_FMT. */
+ return -EINVAL;
+ }
+
bttv_switch_type(fh,V4L2_BUF_TYPE_VBI_CAPTURE);
- return fh->lines * 2 * 2048;
+ return (fh->vbi_fmt.fmt.count[0] * 2
+ * fh->vbi_fmt.fmt.samples_per_line);
+ }
+
default:
return video_usercopy(inode, file, cmd, arg, bttv_do_ioctl);
}
@@ -3017,10 +3630,14 @@ static ssize_t bttv_read(struct file *file, char __user *data,
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (locked_btres(fh->btv,RESOURCE_VIDEO))
+ if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+ /* VIDEO_READ in use by another fh,
+ or VIDEO_STREAM by any fh. */
return -EBUSY;
+ }
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
+ free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3046,7 +3663,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
return videobuf_poll_stream(file, &fh->vbi, wait);
}
- if (check_btres(fh,RESOURCE_VIDEO)) {
+ if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
/* streaming capture */
if (list_empty(&fh->cap.stream))
return POLLERR;
@@ -3056,7 +3673,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
mutex_lock(&fh->cap.lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
- if (locked_btres(fh->btv,RESOURCE_VIDEO)) {
+ if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) {
mutex_unlock(&fh->cap.lock);
return POLLERR;
}
@@ -3142,8 +3759,23 @@ static int bttv_open(struct inode *inode, struct file *file)
i2c_vidiocschan(btv);
btv->users++;
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
- bttv_vbi_setlines(fh,btv,16);
+
+ /* The V4L2 spec requires one global set of cropping parameters
+ which only change on request. These are stored in btv->crop[1].
+ However for compatibility with V4L apps and cropping unaware
+ V4L2 apps we now reset the cropping parameters as seen through
+ this fh, which is to say VIDIOC_G_CROP and scaling limit checks
+ will use btv->crop[0], the default cropping parameters for the
+ current video standard, and VIDIOC_S_FMT will not implicitely
+ change the cropping parameters until VIDIOC_S_CROP has been
+ called. */
+ fh->do_crop = !reset_crop; /* module parameter */
+
+ /* Likewise there should be one global set of VBI capture
+ parameters, but for compatibility with V4L apps and earlier
+ driver versions each fh has its own parameters. */
+ bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
+
bttv_field_count(btv);
return 0;
}
@@ -3158,14 +3790,17 @@ static int bttv_release(struct inode *inode, struct file *file)
bttv_switch_overlay(btv,fh,NULL);
/* stop video capture */
- if (check_btres(fh, RESOURCE_VIDEO)) {
+ if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
- free_btres(btv,fh,RESOURCE_VIDEO);
+ free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
+ if (check_btres(fh, RESOURCE_VIDEO_READ)) {
+ free_btres(btv, fh, RESOURCE_VIDEO_READ);
+ }
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
@@ -4034,7 +4669,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* initialize structs / fill in defaults */
mutex_init(&btv->lock);
- mutex_init(&btv->reslock);
spin_lock_init(&btv->s_lock);
spin_lock_init(&btv->gpio_lock);
init_waitqueue_head(&btv->gpioq);
@@ -4136,7 +4770,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->init.fmt = format_by_palette(VIDEO_PALETTE_RGB24);
btv->init.width = 320;
btv->init.height = 240;
- btv->init.lines = 16;
btv->input = 0;
/* initialize hardware */
@@ -4171,6 +4804,10 @@ static int __devinit bttv_probe(struct pci_dev *dev,
bt848_sat(btv,32768);
audio_mute(btv, 1);
set_input(btv,0);
+ bttv_crop_reset(&btv->crop[0], btv->tvnorm);
+ btv->crop[1] = btv->crop[0]; /* current = default */
+ disclaim_vbi_lines(btv);
+ disclaim_video_lines(btv);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
diff --git a/linux/drivers/media/video/bt8xx/bttv-risc.c b/linux/drivers/media/video/bt8xx/bttv-risc.c
index 824e17d2a..a52b2bf28 100644
--- a/linux/drivers/media/video/bt8xx/bttv-risc.c
+++ b/linux/drivers/media/video/bt8xx/bttv-risc.c
@@ -43,7 +43,8 @@ int
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int padding, unsigned int lines)
+ unsigned int padding, unsigned int skip_lines,
+ unsigned int store_lines)
{
u32 instructions,line,todo;
struct scatterlist *sg;
@@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
one write per scan line + sync + jump (all 2 dwords). padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
- instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
+ instructions = skip_lines * 4;
+ instructions += (1 + ((bpl + padding) * store_lines)
+ / PAGE_SIZE + store_lines) * 8;
+ instructions += 2 * 8;
+ if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
return rc;
/* sync instruction */
@@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
*(rp++) = cpu_to_le32(0);
+ while (skip_lines-- > 0) {
+ *(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
+ BT848_RISC_EOL | bpl);
+ }
+
/* scan lines */
sg = sglist;
- for (line = 0; line < lines; line++) {
+ for (line = 0; line < store_lines; line++) {
if ((btv->opt_vcr_hack) &&
- (line >= (lines - VCR_HACK_LINES)))
+ (line >= (store_lines - VCR_HACK_LINES)))
continue;
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
@@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* estimate risc mem: worst case is one write per page border +
one write per scan line (5 dwords)
plus sync + jump (2 dwords) */
- instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
+ instructions = ((3 + (ybpl + ypadding) * ylines * 2)
+ / PAGE_SIZE) + ylines;
instructions += 2;
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
return rc;
@@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
/* ---------------------------------------------------------- */
static void
-bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
- int width, int height, int interleaved, int norm)
+bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
+ int width, int height, int interleaved,
+ const struct bttv_tvnorm *tvnorm)
{
- const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
u32 xsf, sr;
int vdelay;
@@ -365,6 +374,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
}
static void
+bttv_calc_geo (struct bttv * btv,
+ struct bttv_geometry * geo,
+ unsigned int width,
+ unsigned int height,
+ int both_fields,
+ const struct bttv_tvnorm * tvnorm,
+ const struct v4l2_rect * crop)
+{
+ unsigned int c_width;
+ unsigned int c_height;
+ u32 sr;
+
+ if ((crop->left == tvnorm->cropcap.defrect.left
+ && crop->top == tvnorm->cropcap.defrect.top
+ && crop->width == tvnorm->cropcap.defrect.width
+ && crop->height == tvnorm->cropcap.defrect.height
+ && width <= tvnorm->swidth /* see PAL-Nc et al */)
+ || bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
+ bttv_calc_geo_old(btv, geo, width, height,
+ both_fields, tvnorm);
+ return;
+ }
+
+ /* For bug compatibility the image size checks permit scale
+ factors > 16. See bttv_crop_calc_limits(). */
+ c_width = min((unsigned int) crop->width, width * 16);
+ c_height = min((unsigned int) crop->height, height * 16);
+
+ geo->width = width;
+ geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
+ /* Even to store Cb first, odd for Cr. */
+ geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
+
+ geo->sheight = c_height;
+ geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
+ sr = c_height >> !both_fields;
+ sr = (sr * 512U + (height >> 1)) / height - 512;
+ geo->vscale = (0x10000UL - sr) & 0x1fff;
+ geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
+ geo->vtotal = tvnorm->vtotal;
+
+ geo->crop = (((geo->width >> 8) & 0x03) |
+ ((geo->hdelay >> 6) & 0x0c) |
+ ((geo->sheight >> 4) & 0x30) |
+ ((geo->vdelay >> 2) & 0xc0));
+
+ if (btv->opt_combfilter) {
+ geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
+ geo->comb = (width < 769) ? 1 : 0;
+ } else {
+ geo->vtc = 0;
+ geo->comb = 0;
+ }
+}
+
+static void
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
{
int off = odd ? 0x80 : 0x00;
@@ -526,16 +591,51 @@ int
bttv_buffer_activate_vbi(struct bttv *btv,
struct bttv_buffer *vbi)
{
- /* vbi capture */
+ struct btcx_riscmem *top;
+ struct btcx_riscmem *bottom;
+ int top_irq_flags;
+ int bottom_irq_flags;
+
+ top = NULL;
+ bottom = NULL;
+ top_irq_flags = 0;
+ bottom_irq_flags = 0;
+
if (vbi) {
+ unsigned int crop, vdelay;
+
vbi->vb.state = STATE_ACTIVE;
list_del(&vbi->vb.queue);
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
- } else {
- bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
- bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
+
+ /* VDELAY is start of video, end of VBI capturing. */
+ crop = btread(BT848_E_CROP);
+ vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
+
+ if (vbi->geo.vdelay > vdelay) {
+ vdelay = vbi->geo.vdelay & 0xfe;
+ crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
+
+ btwrite(vdelay, BT848_E_VDELAY_LO);
+ btwrite(crop, BT848_E_CROP);
+ btwrite(vdelay, BT848_O_VDELAY_LO);
+ btwrite(crop, BT848_O_CROP);
+ }
+
+ if (vbi->vbi_count[0] > 0) {
+ top = &vbi->top;
+ top_irq_flags = 4;
+ }
+
+ if (vbi->vbi_count[1] > 0) {
+ top_irq_flags = 0;
+ bottom = &vbi->bottom;
+ bottom_irq_flags = 4;
+ }
}
+
+ bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
+ bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
+
return 0;
}
@@ -615,28 +715,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
int bpf = bpl * (buf->vb.height >> 1);
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
- V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
+ V4L2_FIELD_HAS_BOTH(buf->vb.field),
+ tvnorm,&buf->crop);
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ /* offset */ 0,bpl,
+ /* padding */ 0,/* skip_lines */ 0,
+ buf->vb.height);
break;
case V4L2_FIELD_BOTTOM:
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height);
+ 0,bpl,0,0,buf->vb.height);
break;
case V4L2_FIELD_INTERLACED:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,bpl,buf->vb.height >> 1);
+ 0,bpl,bpl,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpl,bpl,bpl,buf->vb.height >> 1);
+ bpl,bpl,bpl,0,buf->vb.height >> 1);
break;
case V4L2_FIELD_SEQ_TB:
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
- 0,bpl,0,buf->vb.height >> 1);
+ 0,bpl,0,0,buf->vb.height >> 1);
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
- bpf,bpl,0,buf->vb.height >> 1);
+ bpf,bpl,0,0,buf->vb.height >> 1);
break;
default:
BUG();
@@ -666,7 +769,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
switch (buf->vb.field) {
case V4L2_FIELD_TOP:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,/* both_fields */ 0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -674,7 +778,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_BOTTOM:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,0,buf->tvnorm);
+ buf->vb.height,0,
+ tvnorm,&buf->crop);
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
0,buf->vb.width,0,buf->vb.height,
uoffset,voffset,buf->fmt->hshift,
@@ -682,7 +787,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_INTERLACED:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -704,7 +810,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
break;
case V4L2_FIELD_SEQ_TB:
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
- buf->vb.height,1,buf->tvnorm);
+ buf->vb.height,1,
+ tvnorm,&buf->crop);
lines = buf->vb.height >> 1;
ypadding = buf->vb.width;
cpadding = buf->vb.width >> buf->fmt->hshift;
@@ -735,11 +842,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
/* build risc code */
buf->vb.field = V4L2_FIELD_SEQ_TB;
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
- 1,buf->tvnorm);
+ 1,tvnorm,&buf->crop);
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, RAW_BPL, 0, RAW_LINES);
+ /* offset */ 0, RAW_BPL, /* padding */ 0,
+ /* skip_lines */ 0, RAW_LINES);
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
+ buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
}
/* copy format info */
@@ -765,7 +873,8 @@ bttv_overlay_risc(struct bttv *btv,
/* calculate geometry */
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
- V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
+ V4L2_FIELD_HAS_BOTH(ov->field),
+ &bttv_tvnorms[ov->tvnorm],&buf->crop);
/* build risc code */
switch (ov->field) {
diff --git a/linux/drivers/media/video/bt8xx/bttv-vbi.c b/linux/drivers/media/video/bt8xx/bttv-vbi.c
index 63676e7bd..cac2273f7 100644
--- a/linux/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/linux/drivers/media/video/bt8xx/bttv-vbi.c
@@ -5,6 +5,9 @@
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
+ Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
+ Sponsored by OPQ Systems AB
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -42,8 +45,15 @@
to be about 244. */
#define VBI_OFFSET 244
+/* 2048 for compatibility with earlier driver versions. The driver
+ really stores 1024 + tvnorm->vbipack * 4 samples per line in the
+ buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
+ is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
+ four bytes of the VBI image. */
+#define VBI_BPL 2048
+
+/* Compatibility. */
#define VBI_DEFLINES 16
-#define VBI_MAXLINES 32
static unsigned int vbibufs = 4;
static unsigned int vbi_debug = 0;
@@ -59,21 +69,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
#define dprintk(fmt, arg...) if (vbi_debug) \
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
+#define IMAGE_SIZE(fmt) \
+ (((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
+
/* ----------------------------------------------------------------------- */
/* vbi risc code + mm */
-static int
-vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
-{
- int bpl = 2048;
-
- bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
- 0, bpl-4, 4, lines);
- bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
- lines * bpl, bpl-4, 4, lines);
- return 0;
-}
-
static int vbi_buffer_setup(struct videobuf_queue *q,
unsigned int *count, unsigned int *size)
{
@@ -82,8 +83,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
if (0 == *count)
*count = vbibufs;
- *size = fh->lines * 2 * 2048;
- dprintk("setup: lines=%d\n",fh->lines);
+
+ *size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
+
+ dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
+ fh->vbi_fmt.fmt.samples_per_line,
+ fh->vbi_fmt.fmt.start[0],
+ fh->vbi_fmt.fmt.start[1],
+ fh->vbi_fmt.fmt.count[0],
+ fh->vbi_fmt.fmt.count[1]);
+
return 0;
}
@@ -94,18 +103,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
struct bttv_fh *fh = q->priv_data;
struct bttv *btv = fh->btv;
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int skip_lines0, skip_lines1, min_vdelay;
+ int redo_dma_risc;
int rc;
- buf->vb.size = fh->lines * 2 * 2048;
+ buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
+ tvnorm = fh->vbi_fmt.tvnorm;
+
+ /* There's no VBI_VDELAY register, RISC must skip the lines
+ we don't want. With default parameters we skip zero lines
+ as earlier driver versions did. The driver permits video
+ standard changes while capturing, so we use vbi_fmt.tvnorm
+ instead of btv->tvnorm to skip zero lines after video
+ standard changes as well. */
+
+ skip_lines0 = 0;
+ skip_lines1 = 0;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0)
+ skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
+ - tvnorm->vbistart[0]));
+ if (fh->vbi_fmt.fmt.count[1] > 0)
+ skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
+ - tvnorm->vbistart[1]));
+
+ redo_dma_risc = 0;
+
+ if (buf->vbi_skip[0] != skip_lines0 ||
+ buf->vbi_skip[1] != skip_lines1 ||
+ buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
+ buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
+ buf->vbi_skip[0] = skip_lines0;
+ buf->vbi_skip[1] = skip_lines1;
+ buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
+ buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
+ redo_dma_risc = 1;
+ }
+
if (STATE_NEEDS_INIT == buf->vb.state) {
+ redo_dma_risc = 1;
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
goto fail;
- if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
- goto fail;
}
+
+ if (redo_dma_risc) {
+ unsigned int bpl, padding, offset;
+
+ bpl = 2044; /* max. vbipack */
+ padding = VBI_BPL - bpl;
+
+ if (fh->vbi_fmt.fmt.count[0] > 0) {
+ rc = bttv_risc_packed(btv, &buf->top,
+ buf->vb.dma.sglist,
+ /* offset */ 0, bpl,
+ padding, skip_lines0,
+ fh->vbi_fmt.fmt.count[0]);
+ if (0 != rc)
+ goto fail;
+ }
+
+ if (fh->vbi_fmt.fmt.count[1] > 0) {
+ offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
+
+ rc = bttv_risc_packed(btv, &buf->bottom,
+ buf->vb.dma.sglist,
+ offset, bpl,
+ padding, skip_lines1,
+ fh->vbi_fmt.fmt.count[1]);
+ if (0 != rc)
+ goto fail;
+ }
+ }
+
+ /* VBI capturing ends at VDELAY, start of video capturing,
+ no matter where the RISC program ends. VDELAY minimum is 2,
+ bounds.top is the corresponding first field line number
+ times two. VDELAY counts half field lines. */
+ min_vdelay = MIN_VDELAY;
+ if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
+ min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
+
+ /* For bttv_buffer_activate_vbi(). */
+ buf->geo.vdelay = min_vdelay;
+
buf->vb.state = STATE_PREPARED;
buf->vb.field = field;
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
@@ -153,69 +237,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
/* ----------------------------------------------------------------------- */
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
+static int
+try_fmt (struct v4l2_vbi_format * f,
+ const struct bttv_tvnorm * tvnorm,
+ __s32 crop_start)
{
- int vdelay;
-
- if (lines < 1)
- lines = 1;
- if (lines > VBI_MAXLINES)
- lines = VBI_MAXLINES;
- fh->lines = lines;
-
- vdelay = btread(BT848_E_VDELAY_LO);
- if (vdelay < lines*2) {
- vdelay = lines*2;
- btwrite(vdelay,BT848_E_VDELAY_LO);
- btwrite(vdelay,BT848_O_VDELAY_LO);
+ __s32 min_start, max_start, max_end, f2_offset;
+ unsigned int i;
+
+ /* For compatibility with earlier driver versions we must pretend
+ the VBI and video capture window may overlap. In reality RISC
+ magic aborts VBI capturing at the first line of video capturing,
+ leaving the rest of the buffer unchanged, usually all zero.
+ VBI capturing must always start before video capturing. >> 1
+ because cropping counts field lines times two. */
+ min_start = tvnorm->vbistart[0];
+ max_start = (crop_start >> 1) - 1;
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ if (min_start > max_start)
+ return -EBUSY;
+
+ BUG_ON(max_start >= max_end);
+
+ f->sampling_rate = tvnorm->Fsc;
+ f->samples_per_line = VBI_BPL;
+ f->sample_format = V4L2_PIX_FMT_GREY;
+ f->offset = VBI_OFFSET;
+
+ f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
+
+ for (i = 0; i < 2; ++i) {
+ if (0 == f->count[i]) {
+ /* No data from this field. We leave f->start[i]
+ alone because VIDIOCSVBIFMT is w/o and EINVALs
+ when a driver does not support exactly the
+ requested parameters. */
+ } else {
+ s64 start, count;
+
+ start = clamp(f->start[i], min_start, max_start);
+ /* s64 to prevent overflow. */
+ count = (s64) f->start[i] + f->count[i] - start;
+ f->start[i] = start;
+ f->count[i] = clamp(count, (s64) 1,
+ max_end - start);
+ }
+
+ min_start += f2_offset;
+ max_start += f2_offset;
+ max_end += f2_offset;
}
+
+ if (0 == (f->count[0] | f->count[1])) {
+ /* As in earlier driver versions. */
+ f->start[0] = tvnorm->vbistart[0];
+ f->start[1] = tvnorm->vbistart[1];
+ f->count[0] = 1;
+ f->count[1] = 1;
+ }
+
+ f->flags = 0;
+
+ f->reserved[0] = 0;
+ f->reserved[1] = 0;
+
+ return 0;
}
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_try_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
- s64 count0,count1,count;
+ __s32 crop_start;
- tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.flags = 0;
-
- /* s64 to prevent overflow. */
- count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
- - tvnorm->vbistart[0];
- count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
- - tvnorm->vbistart[1];
- count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
-
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = count;
- f->fmt.vbi.count[1] = count;
-
- f->fmt.vbi.reserved[0] = 0;
- f->fmt.vbi.reserved[1] = 0;
+ mutex_lock(&btv->lock);
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+ crop_start = btv->crop_start;
+
+ mutex_unlock(&btv->lock);
+
+ return try_fmt(f, tvnorm, crop_start);
}
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
+int
+bttv_vbi_set_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
{
+ struct bttv *btv = fh->btv;
const struct bttv_tvnorm *tvnorm;
+ __s32 start1, end;
+ int rc;
+
+ mutex_lock(&btv->lock);
+
+ rc = -EBUSY;
+ if (fh->resources & RESOURCE_VBI)
+ goto fail;
+
+ tvnorm = &bttv_tvnorms[btv->tvnorm];
+
+ rc = try_fmt(f, tvnorm, btv->crop_start);
+ if (0 != rc)
+ goto fail;
+
+ start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
+
+ /* First possible line of video capturing. Should be
+ max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
+ when capturing both fields. But for compatibility we must
+ pretend the VBI and video capture window may overlap,
+ so end = start + 1, the lowest possible value, times two
+ because vbi_fmt.end counts field lines times two. */
+ end = max(f->start[0], start1) * 2 + 2;
+
+ mutex_lock(&fh->vbi.lock);
+
+ fh->vbi_fmt.fmt = *f;
+ fh->vbi_fmt.tvnorm = tvnorm;
+ fh->vbi_fmt.end = end;
+
+ mutex_unlock(&fh->vbi.lock);
+
+ rc = 0;
+
+ fail:
+ mutex_unlock(&btv->lock);
+
+ return rc;
+}
+
+void
+bttv_vbi_get_fmt (struct bttv_fh * fh,
+ struct v4l2_vbi_format * f)
+{
+ const struct bttv_tvnorm *tvnorm;
+
+ *f = fh->vbi_fmt.fmt;
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = tvnorm->Fsc;
- f->fmt.vbi.samples_per_line = 2048;
- f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = VBI_OFFSET;
- f->fmt.vbi.start[0] = tvnorm->vbistart[0];
- f->fmt.vbi.start[1] = tvnorm->vbistart[1];
- f->fmt.vbi.count[0] = fh->lines;
- f->fmt.vbi.count[1] = fh->lines;
- f->fmt.vbi.flags = 0;
+
+ if (tvnorm != fh->vbi_fmt.tvnorm) {
+ __s32 max_end;
+ unsigned int i;
+
+ /* As in vbi_buffer_prepare() this imitates the
+ behaviour of earlier driver versions after video
+ standard changes, with default parameters anyway. */
+
+ max_end = (tvnorm->cropcap.bounds.top
+ + tvnorm->cropcap.bounds.height) >> 1;
+
+ f->sampling_rate = tvnorm->Fsc;
+
+ for (i = 0; i < 2; ++i) {
+ __s32 new_start;
+
+ new_start = f->start[i]
+ + tvnorm->vbistart[i]
+ - fh->vbi_fmt.tvnorm->vbistart[i];
+
+ f->start[i] = min(new_start, max_end - 1);
+ f->count[i] = min((__s32) f->count[i],
+ max_end - f->start[i]);
+
+ max_end += tvnorm->vbistart[1]
+ - tvnorm->vbistart[0];
+ }
+ }
+}
+
+void
+bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f,
+ int norm)
+{
+ const struct bttv_tvnorm *tvnorm;
+ unsigned int real_samples_per_line;
+ unsigned int real_count;
+
+ tvnorm = &bttv_tvnorms[norm];
+
+ f->fmt.sampling_rate = tvnorm->Fsc;
+ f->fmt.samples_per_line = VBI_BPL;
+ f->fmt.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.offset = VBI_OFFSET;
+ f->fmt.start[0] = tvnorm->vbistart[0];
+ f->fmt.start[1] = tvnorm->vbistart[1];
+ f->fmt.count[0] = VBI_DEFLINES;
+ f->fmt.count[1] = VBI_DEFLINES;
+ f->fmt.flags = 0;
+ f->fmt.reserved[0] = 0;
+ f->fmt.reserved[1] = 0;
+
+ /* For compatibility the buffer size must be 2 * VBI_DEFLINES *
+ VBI_BPL regardless of the current video standard. */
+ real_samples_per_line = 1024 + tvnorm->vbipack * 4;
+ real_count = ((tvnorm->cropcap.defrect.top >> 1)
+ - tvnorm->vbistart[0]);
+
+ BUG_ON(real_samples_per_line > VBI_BPL);
+ BUG_ON(real_count > VBI_DEFLINES);
+
+ f->tvnorm = tvnorm;
+
+ /* See bttv_vbi_fmt_set(). */
+ f->end = tvnorm->vbistart[0] * 2 + 2;
}
/* ----------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h
index 70f9f879c..a273c424b 100644
--- a/linux/drivers/media/video/bt8xx/bttvp.h
+++ b/linux/drivers/media/video/bt8xx/bttvp.h
@@ -27,7 +27,7 @@
#include "compat.h"
#include <linux/version.h>
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
#include <linux/types.h>
#include <linux/wait.h>
@@ -75,14 +75,22 @@
#define RISC_SLOT_LOOP 14
#define RESOURCE_OVERLAY 1
-#define RESOURCE_VIDEO 2
+#define RESOURCE_VIDEO_STREAM 2
#define RESOURCE_VBI 4
+#define RESOURCE_VIDEO_READ 8
#define RAW_LINES 640
#define RAW_BPL 1024
#define UNSET (-1U)
+/* Min. value in VDELAY register. */
+#define MIN_VDELAY 2
+/* Even to get Cb first, odd for Cr. */
+#define MAX_HDELAY (0x3FF & -2)
+/* Limits scaled width, which must be a multiple of 4. */
+#define MAX_HACTIVE (0x3FF & -4)
+
#define clamp(x, low, high) min (max (low, x), high)
/* ---------------------------------------------------------- */
@@ -101,8 +109,13 @@ struct bttv_tvnorm {
u16 vtotal;
int sram;
/* ITU-R frame line number of the first VBI line we can
- capture, of the first and second field. */
+ capture, of the first and second field. The last possible line
+ is determined by cropcap.bounds. */
u16 vbistart[2];
+ /* Horizontally this counts fCLKx1 samples following the leading
+ edge of the horizontal sync pulse, vertically ITU-R frame line
+ numbers of the first field times two (2, 4, 6, ... 524 or 624). */
+ struct v4l2_cropcap cropcap;
};
extern const struct bttv_tvnorm bttv_tvnorms[];
@@ -137,6 +150,9 @@ struct bttv_buffer {
struct bttv_geometry geo;
struct btcx_riscmem top;
struct btcx_riscmem bottom;
+ struct v4l2_rect crop;
+ unsigned int vbi_skip[2];
+ unsigned int vbi_count[2];
};
struct bttv_buffer_set {
@@ -155,6 +171,34 @@ struct bttv_overlay {
int setup_ok;
};
+struct bttv_vbi_fmt {
+ struct v4l2_vbi_format fmt;
+
+ /* fmt.start[] and count[] refer to this video standard. */
+ const struct bttv_tvnorm *tvnorm;
+
+ /* Earliest possible start of video capturing with this
+ v4l2_vbi_format, in struct bttv_crop.rect units. */
+ __s32 end;
+};
+
+/* bttv-vbi.c */
+void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
+
+struct bttv_crop {
+ /* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
+ struct v4l2_rect rect;
+
+ /* Scaled image size limits with this crop rect. Divide
+ max_height, but not min_height, by two when capturing
+ single fields. See also bttv_crop_reset() and
+ bttv_crop_adjust() in bttv-driver.c. */
+ __s32 min_scaled_width;
+ __s32 min_scaled_height;
+ __s32 max_scaled_width;
+ __s32 max_scaled_height;
+};
+
struct bttv_fh {
struct bttv *btv;
int resources;
@@ -169,13 +213,19 @@ struct bttv_fh {
int width;
int height;
- /* current settings */
+ /* video overlay */
const struct bttv_format *ovfmt;
struct bttv_overlay ov;
- /* video overlay */
+ /* Application called VIDIOC_S_CROP. */
+ int do_crop;
+
+ /* vbi capture */
struct videobuf_queue vbi;
- int lines;
+ /* Current VBI capture window as seen through this fh (cannot
+ be global for compatibility with earlier drivers). Protected
+ by struct bttv.lock and struct bttv_fh.vbi.lock. */
+ struct bttv_vbi_fmt vbi_fmt;
};
/* ---------------------------------------------------------- */
@@ -185,7 +235,8 @@ struct bttv_fh {
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
struct scatterlist *sglist,
unsigned int offset, unsigned int bpl,
- unsigned int pitch, unsigned int lines);
+ unsigned int pitch, unsigned int skip_lines,
+ unsigned int store_lines);
/* control dma register + risc main loop */
void bttv_set_dma(struct bttv *btv, int override);
@@ -211,9 +262,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
/* ---------------------------------------------------------- */
/* bttv-vbi.c */
-void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
-void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
+int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
+int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
extern struct videobuf_queue_ops bttv_vbi_qops;
@@ -244,7 +295,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
#define BTTV_FREE_IDLE (HZ) /* one second */
@@ -332,11 +382,6 @@ struct bttv {
struct mutex lock;
#endif
int resources;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
- struct semaphore reslock;
-#else
- struct mutex reslock;
-#endif
#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
#endif
@@ -406,6 +451,21 @@ struct bttv {
unsigned int users;
struct bttv_fh init;
+
+ /* Default (0) and current (1) video capturing and overlay
+ cropping parameters in bttv_tvnorm.cropcap units. Protected
+ by bttv.lock. */
+ struct bttv_crop crop[2];
+
+ /* Earliest possible start of video capturing in
+ bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 vbi_end;
+
+ /* Latest possible end of VBI capturing (= crop[x].rect.top when
+ VIDEO_RESOURCES are locked). Set by check_alloc_btres()
+ and free_btres(). Protected by bttv.lock. */
+ __s32 crop_start;
};
/* our devices */
diff --git a/linux/drivers/media/video/cpia.c b/linux/drivers/media/video/cpia.c
index 9214c15c4..2494bb844 100644
--- a/linux/drivers/media/video/cpia.c
+++ b/linux/drivers/media/video/cpia.c
@@ -1353,13 +1353,13 @@ out:
static void create_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
struct proc_dir_entry *ent;
if (!cpia_proc_root || !cam)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
if (!ent)
@@ -1379,12 +1379,12 @@ static void create_proc_cpia_cam(struct cam_data *cam)
static void destroy_proc_cpia_cam(struct cam_data *cam)
{
- char name[7];
+ char name[5 + 1 + 10 + 1];
if (!cam || !cam->proc_entry)
return;
- sprintf(name, "video%d", cam->vdev.minor);
+ snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
remove_proc_entry(name, cpia_proc_root);
cam->proc_entry = NULL;
}
diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c
index 896beb7ed..3bb0a80de 100644
--- a/linux/drivers/media/video/cx88/cx88-blackbird.c
+++ b/linux/drivers/media/video/cx88/cx88-blackbird.c
@@ -6,6 +6,9 @@
* (c) 2004 Jelle Foks <jelle@foks.8m.com>
* (c) 2004 Gerd Knorr <kraxel@bytesex.org>
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - video_ioctl2 conversion
+ *
* Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
*
* This program is free software; you can redistribute it and/or modify
@@ -531,7 +534,7 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
dev->params.width = dev->width;
dev->params.height = dev->height;
- dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+ dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
}
@@ -729,8 +732,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
return 0;
}
-static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
+/* ------------------------------------------------------------------ */
+/* IOCTL Handlers */
+
+static int vidioc_querymenu (struct file *file, void *priv,
+ struct v4l2_querymenu *qmenu)
{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
struct v4l2_queryctrl qctrl;
qctrl.id = qmenu->id;
@@ -738,235 +746,355 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
}
-/* ------------------------------------------------------------------ */
-
-static int mpeg_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
struct cx88_core *core = dev->core;
- if (debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
-
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx88_blackbird");
- strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
+ strcpy(cap->driver, "cx88_blackbird");
+ strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
#if 0
- V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_OVERLAY |
#endif
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
- return 0;
- }
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- int index;
-
- index = f->index;
- if (index != 0)
- return -EINVAL;
-
- memset(f,0,sizeof(*f));
- f->index = index;
- strlcpy(f->description, "MPEG", sizeof(f->description));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->pixelformat = V4L2_PIX_FMT_MPEG;
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
-
- memset(f,0,sizeof(*f));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
- dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
- return 0;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
-
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
- f->fmt.pix.colorspace = 0;
-#if 0
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
- fh->mpegq.field = f->fmt.pix.field;
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->width;
+ f->fmt.pix.height = dev->height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+ dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->width, dev->height, fh->mpegq.field );
+ return 0;
+}
+
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
+ f->fmt.pix.colorspace = 0;
+#if 1
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ fh->mpegq.field = f->fmt.pix.field;
#endif
-#if 0
- cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
- blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
- f->fmt.pix.height, f->fmt.pix.width);
+#if 1
+ cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ f->fmt.pix.height, f->fmt.pix.width);
#endif
- dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
- return 0;
- }
+ dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
+ return 0;
+}
- /* --- streaming capture ------------------------------------- */
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(&fh->mpegq, arg);
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_reqbufs(&fh->mpegq, p));
+}
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(&fh->mpegq, arg);
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_querybuf(&fh->mpegq, p));
+}
- case VIDIOC_QBUF:
- return videobuf_qbuf(&fh->mpegq, arg);
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_qbuf(&fh->mpegq, p));
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(&fh->mpegq, arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8802_fh *fh = priv;
+ return (videobuf_dqbuf(&fh->mpegq, p,
+ file->f_flags & O_NONBLOCK));
+}
- case VIDIOC_STREAMON:
- return videobuf_streamon(&fh->mpegq);
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamon(&fh->mpegq);
+}
- case VIDIOC_STREAMOFF:
- return videobuf_streamoff(&fh->mpegq);
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8802_fh *fh = priv;
+ return videobuf_streamoff(&fh->mpegq);
+}
- /* --- mpeg compression -------------------------------------- */
- case VIDIOC_G_MPEGCOMP:
- {
- struct v4l2_mpeg_compression *f = arg;
+static int vidioc_g_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
+ memcpy(f,&default_mpeg_params,sizeof(*f));
+ return 0;
+}
- printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_G_EXT_CTRLS!");
- memcpy(f,&default_mpeg_params,sizeof(*f));
- return 0;
- }
- case VIDIOC_S_MPEGCOMP:
- printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
- "Replace with VIDIOC_S_EXT_CTRLS!");
- return 0;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
+static int vidioc_s_mpegcomp (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *f)
+{
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
+ return 0;
+}
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- return cx2341x_ext_ctrls(&dev->params, f, cmd);
- }
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *f = arg;
- struct cx2341x_mpeg_params p;
- int err;
-
- if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
- return -EINVAL;
- p = dev->params;
- err = cx2341x_ext_ctrls(&p, f, cmd);
- if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
- err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
- dev->params = p;
- }
- return err;
- }
- case VIDIOC_S_FREQUENCY:
- {
- blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
- BLACKBIRD_END_NOW,
- BLACKBIRD_MPEG_CAPTURE,
- BLACKBIRD_RAW_BITS_NONE);
-
- cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
-
- blackbird_initialize_codec(dev);
- cx88_set_scale(dev->core, dev->width, dev->height,
- fh->mpegq.field);
- return 0;
+static int vidioc_g_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+ if (!err) {
+ err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+ dev->params = p;
}
- case VIDIOC_LOG_STATUS:
- {
- char name[32 + 2];
-
- snprintf(name, sizeof(name), "%s/2", core->name);
- printk("%s/2: ============ START LOG STATUS ============\n",
- core->name);
- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
- cx2341x_log_status(&dev->params, name);
- printk("%s/2: ============= END LOG STATUS =============\n",
- core->name);
+ return err;
+}
+
+static int vidioc_try_ext_ctrls (struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+
+ return err;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx8802_dev *dev = fh->dev;
+ struct cx88_core *core = dev->core;
+
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE);
+ cx88_set_freq (core,f);
+ blackbird_initialize_codec(dev);
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+ return 0;
+}
+
+static int vidioc_log_status (struct file *file, void *priv)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+ struct cx88_core *core = dev->core;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
+ return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
+
+ if (blackbird_queryctrl(dev, qctrl) == 0)
return 0;
- }
- case VIDIOC_QUERYMENU:
- return blackbird_querymenu(dev, arg);
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- if (blackbird_queryctrl(dev, c) == 0)
- return 0;
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
- }
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
- default:
- return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
- }
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8802_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+
+ return 0;
+}
+
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ *i = core->input;
+ return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (i >= 4)
+ return -EINVAL;
+
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
return 0;
}
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ u32 reg;
+
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
-static unsigned int mpeg_translate_ioctl(unsigned int cmd)
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
{
- return cmd;
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
}
-static int mpeg_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
{
- cmd = cx88_ioctl_translator( cmd );
- return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+ struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*id);
+ mutex_unlock(&core->lock);
+ return 0;
}
+/* FIXME: cx88_ioctl_hook not implemented */
+
static int mpeg_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
@@ -1092,17 +1220,47 @@ static struct file_operations mpeg_fops =
.read = mpeg_read,
.poll = mpeg_poll,
.mmap = mpeg_mmap,
- .ioctl = mpeg_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
};
static struct video_device cx8802_mpeg_template =
{
- .name = "cx8802",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
- .hardware = 0,
- .fops = &mpeg_fops,
- .minor = -1,
+ .name = "cx8802",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
+ .fops = &mpeg_fops,
+ .minor = -1,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_mpegcomp = vidioc_g_mpegcomp,
+ .vidioc_s_mpegcomp = vidioc_s_mpegcomp,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_s_std = vidioc_s_std,
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
/* ------------------------------------------------------------------ */
@@ -1200,7 +1358,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
cx2341x_fill_defaults(&dev->params);
dev->params.port = CX2341X_PORT_STREAMING;
- if (core->tvnorm->id & V4L2_STD_525_60) {
+ cx8802_mpeg_template.current_norm = core->tvnorm;
+
+ if (core->tvnorm & V4L2_STD_525_60) {
dev->height = 480;
} else {
dev->height = 576;
@@ -1214,25 +1374,12 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
blackbird_register_video(dev);
/* initial device configuration: needed ? */
-#if 0
- down(&dev->lock);
- init_controls(core);
-/* #if 1 */
- /* force norm to PAL */
- {
- int i;
- for (i = 0; i < TVNORMS; i++)
- if (tvnorms[i].id == V4L2_STD_PAL_BG)
- {
- cx88_set_tvnorm(core,&tvnorms[i]);
- break;
- }
- }
-/* #else */
- cx88_set_tvnorm(core,tvnorms);
-/* #endif */
- video_mux(core,0);
- up(&dev->lock);
+#if 1
+ mutex_lock(&dev->core->lock);
+// init_controls(core);
+ cx88_set_tvnorm(core,core->tvnorm);
+ cx88_video_mux(core,0);
+ mutex_unlock(&dev->core->lock);
#endif
return 0;
@@ -1268,8 +1415,6 @@ static int blackbird_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- cx88_ioctl_hook = mpeg_do_ioctl;
- cx88_ioctl_translator = mpeg_translate_ioctl;
return cx8802_register_driver(&cx8802_blackbird_driver);
}
@@ -1281,8 +1426,8 @@ static void blackbird_fini(void)
module_init(blackbird_init);
module_exit(blackbird_fini);
-EXPORT_SYMBOL(cx88_ioctl_hook);
-EXPORT_SYMBOL(cx88_ioctl_translator);
+module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
+MODULE_PARM_DESC(debug,"enable debug messages [video]");
/* ----------------------------------------------------------- */
/*
diff --git a/linux/drivers/media/video/cx88/cx88-core.c b/linux/drivers/media/video/cx88/cx88-core.c
index fc8dbebbc..367dc3c7b 100644
--- a/linux/drivers/media/video/cx88/cx88-core.c
+++ b/linux/drivers/media/video/cx88/cx88-core.c
@@ -5,6 +5,11 @@
*
* (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -671,30 +676,30 @@ int cx88_reset(struct cx88_core *core)
/* ------------------------------------------------------------------ */
-static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
+static unsigned int inline norm_swidth(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
}
-static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_hdelay(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
}
-static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vdelay(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
+ return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
}
-static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
+static unsigned int inline norm_fsc8(v4l2_std_id norm)
{
- if (norm->id & V4L2_STD_PAL_M)
+ if (norm & V4L2_STD_PAL_M)
return 28604892; // 3.575611 MHz
- if (norm->id & (V4L2_STD_PAL_Nc))
+ if (norm & (V4L2_STD_PAL_Nc))
return 28656448; // 3.582056 MHz
- if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
+ if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
return 28636360; // 3.57954545 MHz +/- 10 Hz
/* SECAM have also different sub carrier for chroma,
@@ -706,20 +711,20 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
return 35468950; // 4.43361875 MHz +/- 5 Hz
}
-static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
+static unsigned int inline norm_htotal(v4l2_std_id norm)
{
unsigned int fsc4=norm_fsc8(norm)/2;
/* returns 4*FSC / vtotal / frames per seconds */
- return (norm->id & V4L2_STD_625_50) ?
+ return (norm & V4L2_STD_625_50) ?
((fsc4+312)/625+12)/25 :
((fsc4+262)/525*1001+15000)/30000;
}
-static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
+static unsigned int inline norm_vbipack(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 400;
+ return (norm & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -732,7 +737,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
V4L2_FIELD_HAS_TOP(field) ? "T" : "",
V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
- core->tvnorm->name);
+ v4l2_norm_to_name(core->tvnorm));
if (!V4L2_FIELD_HAS_BOTH(field))
height *= 2;
@@ -769,7 +774,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
// setup filters
value = 0;
value |= (1 << 19); // CFILT (default)
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
value |= (1 << 15);
value |= (1 << 16);
}
@@ -866,36 +871,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
static int set_tvaudio(struct cx88_core *core)
{
- struct cx88_tvnorm *norm = core->tvnorm;
+ v4l2_std_id norm = core->tvnorm;
if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
return 0;
- if (V4L2_STD_PAL_BG & norm->id) {
+ if (V4L2_STD_PAL_BG & norm) {
core->tvaudio = WW_BG;
- } else if (V4L2_STD_PAL_DK & norm->id) {
+ } else if (V4L2_STD_PAL_DK & norm) {
core->tvaudio = WW_DK;
- } else if (V4L2_STD_PAL_I & norm->id) {
+ } else if (V4L2_STD_PAL_I & norm) {
core->tvaudio = WW_I;
- } else if (V4L2_STD_SECAM_L & norm->id) {
+ } else if (V4L2_STD_SECAM_L & norm) {
core->tvaudio = WW_L;
- } else if (V4L2_STD_SECAM_DK & norm->id) {
+ } else if (V4L2_STD_SECAM_DK & norm) {
core->tvaudio = WW_DK;
- } else if ((V4L2_STD_NTSC_M & norm->id) ||
- (V4L2_STD_PAL_M & norm->id)) {
+ } else if ((V4L2_STD_NTSC_M & norm) ||
+ (V4L2_STD_PAL_M & norm)) {
core->tvaudio = WW_BTSC;
- } else if (V4L2_STD_NTSC_M_JP & norm->id) {
+ } else if (V4L2_STD_NTSC_M_JP & norm) {
core->tvaudio = WW_EIAJ;
} else {
printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
- core->name, norm->name);
+ core->name, v4l2_norm_to_name(core->tvnorm));
core->tvaudio = 0;
return 0;
}
@@ -916,7 +921,7 @@ static int set_tvaudio(struct cx88_core *core)
-int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
+int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
{
u32 fsc8;
u32 adc_clock;
@@ -924,6 +929,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
u32 step_db,step_dr;
u64 tmp64;
u32 bdelay,agcdelay,htotal;
+ u32 cxiformat, cxoformat;
core->tvnorm = norm;
fsc8 = norm_fsc8(norm);
@@ -932,24 +938,52 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
step_db = fsc8;
step_dr = fsc8;
- if (norm->id & V4L2_STD_SECAM) {
+ if (norm & V4L2_STD_NTSC_M_JP) {
+ cxiformat = VideoFormatNTSCJapan;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC_443) {
+ cxiformat = VideoFormatNTSC443;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_PAL_M) {
+ cxiformat = VideoFormatPALM;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_N) {
+ cxiformat = VideoFormatPALN;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_Nc) {
+ cxiformat = VideoFormatPALNC;
+ cxoformat = 0x1c1f0008;
+ } else if (norm & V4L2_STD_PAL_60) {
+ cxiformat = VideoFormatPAL60;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_NTSC) {
+ cxiformat = VideoFormatNTSC;
+ cxoformat = 0x181f0008;
+ } else if (norm & V4L2_STD_SECAM) {
step_db = 4250000 * 8;
step_dr = 4406250 * 8;
+
+ cxiformat = VideoFormatSECAM;
+ cxoformat = 0x181f0008;
+ } else { /* PAL */
+ cxiformat = VideoFormatPAL;
+ cxoformat = 0x181f0008;
}
dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
- norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
+ v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
+ step_db, step_dr);
set_pll(core,2,vdec_clock);
dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
+ cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
+ cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
#if 1
// FIXME: as-is from DScaler
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
- norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
- cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
+ cxoformat, cx_read(MO_OUTPUT_FORMAT));
+ cx_write(MO_OUTPUT_FORMAT, cxoformat);
#endif
// MO_SCONV_REG = adc clock / video dec clock * 2^17
@@ -999,7 +1033,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
set_tvaudio(core);
// tell i2c chips
- cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
+ cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
// done
return 0;
diff --git a/linux/drivers/media/video/cx88/cx88-vbi.c b/linux/drivers/media/video/cx88/cx88-vbi.c
index 5cd0ee9ce..d22c5f8cf 100644
--- a/linux/drivers/media/video/cx88/cx88-vbi.c
+++ b/linux/drivers/media/video/cx88/cx88-vbi.c
@@ -22,9 +22,11 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
/* ------------------------------------------------------------------ */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- memset(&f->fmt.vbi,0,sizeof(f->fmt.vbi));
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -32,18 +34,19 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
- if (dev->core->tvnorm->id & V4L2_STD_525_60) {
+ if (dev->core->tvnorm & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
- } else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
+ } else if (dev->core->tvnorm & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
f->fmt.vbi.start[0] = 7 -1;
f->fmt.vbi.start[1] = 319 -1;
}
+ return 0;
}
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c
index 6a420d6db..8a33b7e16 100644
--- a/linux/drivers/media/video/cx88/cx88-video.c
+++ b/linux/drivers/media/video/cx88/cx88-video.c
@@ -1,3 +1,4 @@
+
/*
*
* device driver for Conexant 2388x based TV cards
@@ -5,6 +6,11 @@
*
* (c) 2003-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * - Multituner support
+ * - video_ioctl2 conversion
+ * - PAL/M fixes
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -96,71 +102,7 @@ static LIST_HEAD(cx8800_devlist);
/* ------------------------------------------------------------------- */
/* static data */
-static struct cx88_tvnorm tvnorms[] = {
- {
- .name = "NTSC-M",
- .id = V4L2_STD_NTSC_M,
- .cxiformat = VideoFormatNTSC,
- .cxoformat = 0x181f0008,
- },{
- .name = "NTSC-JP",
- .id = V4L2_STD_NTSC_M_JP,
- .cxiformat = VideoFormatNTSCJapan,
- .cxoformat = 0x181f0008,
-#if 0
- },{
- .name = "NTSC-4.43",
- .id = FIXME,
- .cxiformat = VideoFormatNTSC443,
- .cxoformat = 0x181f0008,
-#endif
- },{
- .name = "PAL-BG",
- .id = V4L2_STD_PAL_BG,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-DK",
- .id = V4L2_STD_PAL_DK,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-I",
- .id = V4L2_STD_PAL_I,
- .cxiformat = VideoFormatPAL,
- .cxoformat = 0x181f0008,
- },{
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- .cxiformat = VideoFormatPALM,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-N",
- .id = V4L2_STD_PAL_N,
- .cxiformat = VideoFormatPALN,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-Nc",
- .id = V4L2_STD_PAL_Nc,
- .cxiformat = VideoFormatPALNC,
- .cxoformat = 0x1c1f0008,
- },{
- .name = "PAL-60",
- .id = V4L2_STD_PAL_60,
- .cxiformat = VideoFormatPAL60,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-L",
- .id = V4L2_STD_SECAM_L,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- },{
- .name = "SECAM-DK",
- .id = V4L2_STD_SECAM_DK,
- .cxiformat = VideoFormatSECAM,
- .cxoformat = 0x181f0008,
- }
-};
+v4l2_std_id radionorms[] = { 0 };
static struct cx8800_fmt formats[] = {
{
@@ -387,14 +329,6 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
}
EXPORT_SYMBOL(cx8800_ctrl_query);
-static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
-{
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
- return cx8800_ctrl_query(qctrl);
-}
-
/* ------------------------------------------------------------------- */
/* resource management */
@@ -447,8 +381,7 @@ void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
/* ------------------------------------------------------------------ */
-/* static int video_mux(struct cx8800_dev *dev, unsigned int input) */
-static int video_mux(struct cx88_core *core, unsigned int input)
+int cx88_video_mux(struct cx88_core *core, unsigned int input)
{
/* struct cx88_core *core = dev->core; */
@@ -487,6 +420,7 @@ static int video_mux(struct cx88_core *core, unsigned int input)
}
return 0;
}
+EXPORT_SYMBOL(cx88_video_mux);
/* ------------------------------------------------------------------ */
@@ -1192,19 +1126,18 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
}
/* ------------------------------------------------------------------ */
+/* VIDEO CTRL IOCTLS */
-/* static int get_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
- struct cx88_ctrl *c = NULL;
+ struct cx88_ctrl *c = NULL;
u32 value;
int i;
for (i = 0; i < CX8800_CTLS; i++)
if (cx8800_ctls[i].v.id == ctl->id)
c = &cx8800_ctls[i];
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg);
@@ -1225,20 +1158,20 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl)
value,c->mask, c->sreg ? " [shadowed]" : "");
return 0;
}
+EXPORT_SYMBOL(cx88_get_control);
-/* static int set_control(struct cx8800_dev *dev, struct v4l2_control *ctl) */
-static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
- /* struct cx88_core *core = dev->core; */
struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
+
for (i = 0; i < CX8800_CTLS; i++) {
if (cx8800_ctls[i].v.id == ctl->id) {
c = &cx8800_ctls[i];
}
}
- if (NULL == c)
+ if (unlikely(NULL == c))
return -EINVAL;
if (ctl->value < c->v.minimum)
@@ -1266,7 +1199,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
value = ((ctl->value - c->off) << c->shift) & c->mask;
- if (core->tvnorm->id & V4L2_STD_SECAM) {
+ if (core->tvnorm & V4L2_STD_SECAM) {
/* For SECAM, both U and V sat should be equal */
value=value<<8|value;
} else {
@@ -1289,6 +1222,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl)
}
return 0;
}
+EXPORT_SYMBOL(cx88_set_control);
static void init_controls(struct cx88_core *core)
{
@@ -1298,681 +1232,562 @@ static void init_controls(struct cx88_core *core)
for (i = 0; i < CX8800_CTLS; i++) {
ctrl.id=cx8800_ctls[i].v.id;
ctrl.value=cx8800_ctls[i].v.default_value;
- set_control(core, &ctrl);
+
+ cx88_set_control(core, &ctrl);
}
}
/* ------------------------------------------------------------------ */
+/* VIDEO IOCTLS */
-static int cx8800_g_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
- return -EINVAL;
- }
+ struct cx8800_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ return 0;
}
-static int cx8800_try_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- struct cx88_core *core = dev->core;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- struct cx8800_fmt *fmt;
- enum v4l2_field field;
- unsigned int maxw, maxh;
-
- fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (NULL == fmt)
- return -EINVAL;
-
- field = f->fmt.pix.field;
- maxw = norm_maxw(core->tvnorm);
- maxh = norm_maxh(core->tvnorm);
-
- if (V4L2_FIELD_ANY == field) {
- field = (f->fmt.pix.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
-
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (NULL == fmt)
+ return -EINVAL;
- f->fmt.pix.field = field;
- if (f->fmt.pix.height < 32)
- f->fmt.pix.height = 32;
- if (f->fmt.pix.height > maxh)
- f->fmt.pix.height = maxh;
- if (f->fmt.pix.width < 48)
- f->fmt.pix.width = 48;
- if (f->fmt.pix.width > maxw)
- f->fmt.pix.width = maxw;
- f->fmt.pix.width &= ~0x03;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
+ field = f->fmt.pix.field;
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
- return 0;
+ if (V4L2_FIELD_ANY == field) {
+ field = (f->fmt.pix.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
}
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
default:
return -EINVAL;
}
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return 0;
}
-static int cx8800_s_fmt(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_format *f)
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- int err;
-
- switch (f->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- err = cx8800_try_fmt(dev,fh,f);
- if (0 != err)
- return err;
+ struct cx8800_fh *fh = priv;
+ int err = vidioc_try_fmt_cap (file,priv,f);
- fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
- return 0;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- cx8800_vbi_fmt(dev, f);
- return 0;
- default:
- return -EINVAL;
- }
+ if (0 != err)
+ return err;
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vidq.field = f->fmt.pix.field;
+ return 0;
}
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others). userspace
- * copying is done already, arg is a kernel pointer.
- */
-static int video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
struct cx88_core *core = dev->core;
- int err;
-
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
- switch (cmd) {
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VBI_CAPTURE |
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities =
#if 0
- V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_VIDEO_OVERLAY |
#endif
- 0;
- if (UNSET != core->tuner_type)
- cap->capabilities |= V4L2_CAP_TUNER;
- return 0;
- }
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VBI_CAPTURE;
+ if (UNSET != core->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (unlikely(f->index >= ARRAY_SIZE(formats)))
+ return -EINVAL;
+
+ strlcpy(f->description,formats[f->index].name,sizeof(f->description));
+ f->pixelformat = formats[f->index].fourcc;
+
+ return 0;
+}
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
-
- index = f->index;
- type = f->type;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index >= ARRAY_SIZE(formats))
- return -EINVAL;
- memset(f,0,sizeof(*f));
- f->index = index;
- f->type = type;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
- f->pixelformat = formats[index].fourcc;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_g_fmt(dev,fh,f);
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_s_fmt(dev,fh,f);
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- return cx8800_try_fmt(dev,fh,f);
- }
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- q = get_queue(fh);
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q,&req);
- if (err < 0)
- return err;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct cx8800_fh *fh = priv;
+ struct videobuf_queue *q;
+ struct v4l2_requestbuffers req;
+ unsigned int i;
+ int err;
+
+ q = get_queue(fh);
+ memset(&req,0,sizeof(req));
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ err = videobuf_reqbufs(q,&req);
+ if (err < 0)
+ return err;
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
+ return 0;
+}
#endif
- case VIDIOC_REQBUFS:
- return videobuf_reqbufs(get_queue(fh), arg);
- case VIDIOC_QUERYBUF:
- return videobuf_querybuf(get_queue(fh), arg);
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_reqbufs(get_queue(fh), p));
+}
- case VIDIOC_QBUF:
- return videobuf_qbuf(get_queue(fh), arg);
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_querybuf(get_queue(fh), p));
+}
- case VIDIOC_DQBUF:
- return videobuf_dqbuf(get_queue(fh), arg,
- file->f_flags & O_NONBLOCK);
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_qbuf(get_queue(fh), p));
+}
- case VIDIOC_STREAMON:
- {
- int res = get_ressource(fh);
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct cx8800_fh *fh = priv;
+ return (videobuf_dqbuf(get_queue(fh), p,
+ file->f_flags & O_NONBLOCK));
+}
- if (!res_get(dev,fh,res))
- return -EBUSY;
- return videobuf_streamon(get_queue(fh));
- }
- case VIDIOC_STREAMOFF:
- {
- int res = get_ressource(fh);
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
- err = videobuf_streamoff(get_queue(fh));
- if (err < 0)
- return err;
- res_free(dev,fh,res);
- return 0;
- }
- default:
- return cx88_do_ioctl( inode, file, fh->radio, core, cmd, arg, video_do_ioctl );
- }
+ if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
+ return -EINVAL;
+ if (unlikely(i != fh->type))
+ return -EINVAL;
+
+ if (unlikely(!res_get(dev,fh,get_ressource(fh))))
+ return -EBUSY;
+ return videobuf_streamon(get_queue(fh));
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx8800_dev *dev = fh->dev;
+ int err, res;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
+
+ res = get_ressource(fh);
+ err = videobuf_streamoff(get_queue(fh));
+ if (err < 0)
+ return err;
+ res_free(dev,fh,res);
return 0;
}
-int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd, void *arg, v4l2_kioctl driver_ioctl)
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
{
- int err;
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- if (video_debug) {
- if (video_debug > 1) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("cx88(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("cx88", cmd);
- }
- } else
- v4l_print_ioctl(core->name,cmd);
-
- }
-
- switch (cmd) {
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
-
- i = e->index;
- if (i >= ARRAY_SIZE(tvnorms))
- return -EINVAL;
- err = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (err < 0)
- return err;
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+ mutex_lock(&core->lock);
+ cx88_set_tvnorm(core,*tvnorms);
+ mutex_unlock(&core->lock);
- *id = core->tvnorm->id;
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
+ return 0;
+}
- for(i = 0; i < ARRAY_SIZE(tvnorms); i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == ARRAY_SIZE(tvnorms))
- return -EINVAL;
+/* only one input in this sample driver */
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
+{
+ static const char *iname[] = {
+ [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
+ [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
+ [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
+ [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
+ [ CX88_VMUX_SVIDEO ] = "S-Video",
+ [ CX88_VMUX_TELEVISION ] = "Television",
+ [ CX88_VMUX_CABLE ] = "Cable TV",
+ [ CX88_VMUX_DVB ] = "DVB",
+ [ CX88_VMUX_DEBUG ] = "for debug only",
+ };
+ unsigned int n;
- mutex_lock(&core->lock);
- cx88_set_tvnorm(core,&tvnorms[i]);
- mutex_unlock(&core->lock);
- return 0;
- }
+ n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ if (0 == INPUT(n)->type)
+ return -EINVAL;
+ memset(i,0,sizeof(*i));
+ i->index = n;
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(i->name,iname[INPUT(n)->type]);
+ if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
+ (CX88_VMUX_CABLE == INPUT(n)->type))
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ i->std = CX88_NORMS;
+ return 0;
+}
+EXPORT_SYMBOL(cx88_enum_input);
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- {
- static const char *iname[] = {
- [ CX88_VMUX_COMPOSITE1 ] = "Composite1",
- [ CX88_VMUX_COMPOSITE2 ] = "Composite2",
- [ CX88_VMUX_COMPOSITE3 ] = "Composite3",
- [ CX88_VMUX_COMPOSITE4 ] = "Composite4",
- [ CX88_VMUX_SVIDEO ] = "S-Video",
- [ CX88_VMUX_TELEVISION ] = "Television",
- [ CX88_VMUX_CABLE ] = "Cable TV",
- [ CX88_VMUX_DVB ] = "DVB",
- [ CX88_VMUX_DEBUG ] = "for debug only",
- };
- struct v4l2_input *i = arg;
- unsigned int n;
-
- n = i->index;
- if (n >= 4)
- return -EINVAL;
- if (0 == INPUT(n)->type)
- return -EINVAL;
- memset(i,0,sizeof(*i));
- i->index = n;
- i->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(i->name,iname[INPUT(n)->type]);
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX88_VMUX_CABLE == INPUT(n)->type))
- i->type = V4L2_INPUT_TYPE_TUNER;
- for (n = 0; n < ARRAY_SIZE(tvnorms); n++)
- i->std |= tvnorms[n].id;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return cx88_enum_input (core,i);
+}
- *i = core->input;
- return 0;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- if (*i >= 4)
- return -EINVAL;
- mutex_lock(&core->lock);
- cx88_newstation(core);
- video_mux(core,*i);
- mutex_unlock(&core->lock);
- return 0;
- }
+ *i = core->input;
+ return 0;
+}
+
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+
+ if (i >= 4)
+ return -EINVAL;
+
+ mutex_lock(&core->lock);
+ cx88_newstation(core);
+ cx88_video_mux(core,i);
+ mutex_unlock(&core->lock);
+ return 0;
+}
#if 0
- /* needs review */
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
- unsigned int n = a->index;
-
- memset(a,0,sizeof(*a));
- a->index = n;
- switch (n) {
- case 0:
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type)
- || (CX88_VMUX_CABLE == INPUT(n)->type)) {
- strcpy(a->name,"Television");
- /* FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. */
- return 0;
- }
- break;
- case 1:
- if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) {
- strcpy(a->name,"Line In");
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
- }
- break;
+static int vidioc_g_audio (struct file *file, void *priv, unsigned int i)
+{
+ struct v4l2_audio *a = arg;
+ unsigned int n = a->index;
+
+ memset(a,0,sizeof(*a));
+ a->index = n;
+ switch (n) {
+ case 0:
+ if ((CX88_VMUX_TELEVISION == INPUT(n)->type)
+ || (CX88_VMUX_CABLE == INPUT(n)->type)) {
+ strcpy(a->name,"Television");
+ /* FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. */
+ return 0;
}
- /* Audio input not available. */
- return -EINVAL;
+ break;
+ case 1:
+ if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->board) {
+ strcpy(a->name,"Line In");
+ a->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+ }
+ break;
}
+ /* Audio input not available. */
+ return -EINVAL;
+}
#endif
- /* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (unlikely(qctrl->id == 0))
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
- return cx88_queryctrl(c);
- }
- case VIDIOC_G_CTRL:
- return get_control(core,arg);
- case VIDIOC_S_CTRL:
- return set_control(core,arg);
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_get_control(core,ctl);
+}
- /* --- tuner ioctls ------------------------------------------ */
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
- u32 reg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Television");
- t->type = V4L2_TUNER_ANALOG_TV;
- t->capability = V4L2_TUNER_CAP_NORM;
- t->rangehigh = 0xffffffffUL;
-
- cx88_get_stereo(core ,t);
- reg = cx_read(MO_DEVICE_STATUS);
- t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ return
+ cx88_set_control(core,ctl);
+}
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
- cx88_set_stereo(core, t->audmode, 1);
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ u32 reg;
- memset(f,0,sizeof(*f));
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- if (UNSET == core->tuner_type)
- return -EINVAL;
+ strcpy(t->name, "Television");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM;
+ t->rangehigh = 0xffffffffUL;
- /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
- f->type = radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
- f->frequency = core->freq;
+ cx88_get_stereo(core ,t);
+ reg = cx_read(MO_DEVICE_STATUS);
+ t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (UNSET == core->tuner_type)
- return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- if (0 == radio && f->type != V4L2_TUNER_ANALOG_TV)
- return -EINVAL;
- if (1 == radio && f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- mutex_lock(&core->lock);
- core->freq = f->frequency;
- cx88_newstation(core);
- cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
-
- /* When changing channels it is required to reset TVAUDIO */
- msleep (10);
- cx88_set_tvaudio(core);
+ if (UNSET == core->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
- mutex_unlock(&core->lock);
- return 0;
- }
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the cx2388x registers */
- case VIDIOC_INT_G_REGISTER:
- {
- struct v4l2_register *reg = arg;
+ cx88_set_stereo(core, t->audmode, 1);
+ return 0;
+}
- if (reg->i2c_id != 0)
- return -EINVAL;
- /* cx2388x has a 24-bit register space */
- reg->val = cx_read(reg->reg&0xffffff);
- return 0;
- }
- case VIDIOC_INT_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- if (reg->i2c_id != 0)
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- cx_write(reg->reg&0xffffff, reg->val);
- return 0;
- }
-#endif
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+
+ /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
+ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
+ f->frequency = core->freq;
+
+ cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
+
+ return 0;
+}
+
+int cx88_set_freq (struct cx88_core *core,
+ struct v4l2_frequency *f)
+{
+ if (unlikely(UNSET == core->tuner_type))
+ return -EINVAL;
+ if (unlikely(f->tuner != 0))
+ return -EINVAL;
+
+ mutex_lock(&core->lock);
+ core->freq = f->frequency;
+ cx88_newstation(core);
+ cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f);
+
+ /* When changing channels it is required to reset TVAUDIO */
+ msleep (10);
+ cx88_set_tvaudio(core);
+
+ mutex_unlock(&core->lock);
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- driver_ioctl);
- }
return 0;
}
+EXPORT_SYMBOL(cx88_set_freq);
-static int video_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
- int retval;
+ struct cx8800_fh *fh = priv;
+ struct cx88_core *core = fh->dev->core;
- retval=video_usercopy(inode, file, cmd, arg, video_do_ioctl);
+ if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV))
+ return -EINVAL;
+ if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
+ return -EINVAL;
- if (video_debug > 1) {
- if (retval < 0) {
- v4l_print_ioctl("cx88(err)", cmd);
- printk(KERN_DEBUG "cx88(err): errcode=%d\n",retval);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("cx88(r)",cmd, (void *)arg);
- }
+ return
+ cx88_set_freq (core,f);
+}
- return retval;
+#if 0 //ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ v4l2_register *reg)
+{
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ /* cx2388x has a 24-bit register space */
+ reg->val = cx_read(reg->reg&0xffffff);
+ return 0;
}
+static int vidioc_s_register (struct file *file, void *fh,
+ v4l2_register *reg)
+{
+
+ if (reg->i2c_id != 0)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ cx_write(reg->reg&0xffffff, reg->val);
+ return 0;
+}
+#endif
+
+/* ----------------------------------------------------------- */
+/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
-static int radio_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int radio_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
struct cx88_core *core = dev->core;
- if (video_debug > 1)
- v4l_print_ioctl(core->name,cmd);
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap,0,sizeof(*cap));
- strcpy(cap->driver, "cx8800");
- strlcpy(cap->card, cx88_boards[core->board].name,
- sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
- cap->version = CX88_VERSION_CODE;
- cap->capabilities = V4L2_CAP_TUNER;
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
+ strcpy(cap->driver, "cx8800");
+ strlcpy(cap->card, cx88_boards[core->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ cap->version = CX88_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_TUNER;
+ return 0;
+}
- if (t->index > 0)
- return -EINVAL;
+static int radio_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
+ if (unlikely(t->index > 0))
+ return -EINVAL;
- cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *i = arg;
+ strcpy(t->name, "Radio");
+ t->type = V4L2_TUNER_RADIO;
- if (i->index != 0)
- return -EINVAL;
- strcpy(i->name,"Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
- return 0;
- }
- case VIDIOC_G_INPUT:
- {
- int *i = arg;
- *i = 0;
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
+ cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t);
+ return 0;
+}
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- return 0;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
- *id = 0;
- return 0;
- }
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
+static int radio_enum_input (struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
+ strcpy(i->name,"Radio");
+ i->type = V4L2_INPUT_TYPE_TUNER;
- if (v->tuner) /* Only tuner 0 */
- return -EINVAL;
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOCSTUNER,v);
- return 0;
- }
-#endif
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *t = arg;
+static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ if (unlikely(a->index))
+ return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
+ memset(a,0,sizeof(*a));
+ strcpy(a->name,"Radio");
+ return 0;
+}
- cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+/* FIXME: Should add a standard for radio */
- return 0;
- }
+static int radio_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
+ if (0 != t->index)
+ return -EINVAL;
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *c = arg;
- int i;
-
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- if (c->id == V4L2_CID_AUDIO_MUTE) {
- for (i = 0; i < CX8800_CTLS; i++)
- if (cx8800_ctls[i].v.id == c->id)
- break;
- *c = cx8800_ctls[i].v;
- } else
- *c = no_ctl;
- return 0;
- }
+ cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t);
+ return 0;
+}
- case VIDIOC_G_CTRL:
- case VIDIOC_S_CTRL:
- case VIDIOC_G_FREQUENCY:
- case VIDIOC_S_FREQUENCY:
- return video_do_ioctl(inode,file,cmd,arg);
+static int radio_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ return 0;
+}
- default:
- return v4l_compat_translate_ioctl(inode,file,cmd,arg,
- radio_do_ioctl);
- }
+static int radio_s_input (struct file *file, void *fh, unsigned int i)
+{
return 0;
-};
+}
-static int radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int radio_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
{
- return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);
-};
+ int i;
+
+ if (c->id < V4L2_CID_BASE ||
+ c->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ if (c->id == V4L2_CID_AUDIO_MUTE) {
+ for (i = 0; i < CX8800_CTLS; i++)
+ if (cx8800_ctls[i].v.id == c->id)
+ break;
+ *c = cx8800_ctls[i].v;
+ } else
+ *c = no_ctl;
+ return 0;
+}
/* ----------------------------------------------------------- */
@@ -2109,29 +1924,50 @@ static struct file_operations video_fops =
.read = video_read,
.poll = video_poll,
.mmap = video_mmap,
- .ioctl = video_ioctl,
+ .ioctl = video_ioctl2,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
#endif
.llseek = no_llseek,
};
+static struct video_device cx8800_vbi_template;
static struct video_device cx8800_video_template =
{
- .name = "cx8800-video",
- .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
-};
-
-static struct video_device cx8800_vbi_template =
-{
- .name = "cx8800-vbi",
- .type = VID_TYPE_TELETEXT|VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &video_fops,
- .minor = -1,
+ .name = "cx8800-video",
+ .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES,
+ .fops = &video_fops,
+ .minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_g_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_try_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_s_fmt_vbi = cx8800_vbi_fmt,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .tvnorms = CX88_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
};
static struct file_operations radio_fops =
@@ -2139,7 +1975,7 @@ static struct file_operations radio_fops =
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
- .ioctl = radio_ioctl,
+ .ioctl = video_ioctl2,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11)
.compat_ioctl = v4l_compat_ioctl32,
#endif
@@ -2148,11 +1984,23 @@ static struct file_operations radio_fops =
static struct video_device cx8800_radio_template =
{
- .name = "cx8800-radio",
- .type = VID_TYPE_TUNER,
- .hardware = 0,
- .fops = &radio_fops,
- .minor = -1,
+ .name = "cx8800-radio",
+ .type = VID_TYPE_TUNER,
+ .hardware = 0,
+ .fops = &radio_fops,
+ .minor = -1,
+ .vidioc_querycap = radio_querycap,
+ .vidioc_g_tuner = radio_g_tuner,
+ .vidioc_enum_input = radio_enum_input,
+ .vidioc_g_audio = radio_g_audio,
+ .vidioc_s_tuner = radio_s_tuner,
+ .vidioc_s_audio = radio_s_audio,
+ .vidioc_s_input = radio_s_input,
+ .vidioc_queryctrl = radio_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
};
/* ----------------------------------------------------------- */
@@ -2187,6 +2035,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
{
struct cx8800_dev *dev;
struct cx88_core *core;
+
int err;
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
@@ -2221,13 +2070,19 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
goto fail_core;
}
+ /* Initialize VBI template */
+ memcpy( &cx8800_vbi_template, &cx8800_video_template,
+ sizeof(cx8800_vbi_template) );
+ strcpy(cx8800_vbi_template.name,"cx8800-vbi");
+ cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER;
+
/* initialize driver struct */
#if 0
/* moved to cx88_core_get */
init_MUTEX(&dev->lock);
#endif
spin_lock_init(&dev->slock);
- core->tvnorm = tvnorms;
+ core->tvnorm = cx8800_video_template.current_norm;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
@@ -2308,9 +2163,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* initial device configuration */
mutex_lock(&core->lock);
- cx88_set_tvnorm(core,tvnorms);
+ cx88_set_tvnorm(core,core->tvnorm);
init_controls(core);
- video_mux(core,0);
+ cx88_video_mux(core,0);
mutex_unlock(&core->lock);
/* start tvaudio thread */
@@ -2499,8 +2354,6 @@ static void cx8800_fini(void)
module_init(cx8800_init);
module_exit(cx8800_fini);
-EXPORT_SYMBOL(cx88_do_ioctl);
-
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index d94a2f7f4..5bb190eb2 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -55,6 +55,13 @@
/* ----------------------------------------------------------- */
/* defines and enums */
+/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
+#define CX88_NORMS (\
+ V4L2_STD_NTSC_M| V4L2_STD_NTSC_M_JP| V4L2_STD_NTSC_443 | \
+ V4L2_STD_PAL_BG| V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \
+ V4L2_STD_PAL_60| V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK )
+
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -87,22 +94,15 @@ enum cx8802_board_access {
/* ----------------------------------------------------------- */
/* tv norms */
-struct cx88_tvnorm {
- char *name;
- v4l2_std_id id;
- u32 cxiformat;
- u32 cxoformat;
-};
-
-static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxw(v4l2_std_id norm)
{
- return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+ return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
}
-static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
+static unsigned int inline norm_maxh(v4l2_std_id norm)
{
- return (norm->id & V4L2_STD_625_50) ? 576 : 480;
+ return (norm & V4L2_STD_625_50) ? 576 : 480;
}
/* ----------------------------------------------------------- */
@@ -329,7 +329,7 @@ struct cx88_core {
/* state info */
struct task_struct *kthread;
- struct cx88_tvnorm *tvnorm;
+ v4l2_std_id tvnorm;
u32 tvaudio;
u32 audiomode_manual;
u32 audiomode_current;
@@ -575,7 +575,7 @@ extern void cx88_sram_channel_dump(struct cx88_core *core,
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
unsigned int height, enum v4l2_field field);
-extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
+extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
@@ -592,7 +592,10 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-vbi.c */
-void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
+int cx8800_vbi_fmt (struct file *file, void *priv,
+ struct v4l2_format *f);
+
/*
int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
@@ -672,19 +675,14 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
int cx8802_resume_common(struct pci_dev *pci_dev);
/* ----------------------------------------------------------- */
-/* cx88-video.c */
-extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
- struct cx88_core *core, unsigned int cmd,
- void *arg, v4l2_kioctl driver_ioctl);
+/* cx88-video.c*/
extern const u32 cx88_user_ctrls[];
extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
-
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c */
-/* used by cx88-ivtv ioctl emulation layer */
-extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
+int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
+int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
+int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
+int cx88_video_mux(struct cx88_core *core, unsigned int input);
/*
* Local variables:
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
index 9d1a126be..7f38dae17 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -32,7 +32,6 @@ struct pvr2_msp3400_handler {
struct pvr2_hdw *hdw;
struct pvr2_i2c_client *client;
struct pvr2_i2c_handler i2c_handler;
- struct pvr2_audio_stat astat;
unsigned long stale_mask;
};
@@ -45,13 +44,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- struct v4l2_tuner vt;
- memset(&vt,0,sizeof(vt));
- vt.audmode = hdw->audiomode_val;
- pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
- }
-
route.input = MSP_INPUT_DEFAULT;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
switch (hdw->input_val) {
@@ -79,8 +71,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
static int check_stereo(struct pvr2_msp3400_handler *ctxt)
{
struct pvr2_hdw *hdw = ctxt->hdw;
- return (hdw->input_dirty ||
- hdw->audiomode_dirty);
+ return hdw->input_dirty;
}
@@ -100,8 +91,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (msp3400_ops[idx].check(ctxt)) {
@@ -117,8 +107,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -127,27 +116,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
}
-/* This reads back the current signal type */
-static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
-{
- struct v4l2_tuner vt;
- int stat;
-
- memset(&vt,0,sizeof(vt));
- stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (stat < 0) return stat;
-
- ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
- ctxt->hdw->flag_bilingual =
- (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
- return 0;
-}
-
-
static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
{
ctxt->client->handler = NULL;
- ctxt->hdw->audio_stat = NULL;
kfree(ctxt);
}
@@ -170,24 +141,17 @@ const static struct pvr2_i2c_handler_functions msp3400_funcs = {
int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
{
struct pvr2_msp3400_handler *ctxt;
- if (hdw->audio_stat) return 0;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &msp3400_funcs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->astat.ctxt = ctxt;
- ctxt->astat.status = (int (*)(void *))get_audio_status;
- ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
- ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
- sizeof(msp3400_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
cp->handler = &ctxt->i2c_handler;
- hdw->audio_stat = &ctxt->astat;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
cp->client->addr);
return !0;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
index 19787dc81..3103c808c 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -95,9 +95,8 @@ struct pvr2_context *pvr2_context_create(
void (*setup_func)(struct pvr2_context *))
{
struct pvr2_context *mp = NULL;
- mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+ mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
- memset(mp,0,sizeof(*mp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 3bff4e8aa..83d1484a9 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -520,9 +520,8 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
- ret = parse_token(
- ptr,len,valptr,boolNames,
- sizeof(boolNames)/sizeof(boolNames[0]));
+ ret = parse_token(ptr,len,valptr,boolNames,
+ ARRAY_SIZE(boolNames));
if (ret == 1) {
*valptr = *valptr ? !0 : 0;
} else if (ret == 0) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index bb2125340..f44048186 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -150,8 +150,7 @@ static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -167,8 +166,7 @@ static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
}
-static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
char *buf,unsigned int cnt)
{
@@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
{
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index f985f00d8..e9da9bb8f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
{
struct debugifc_mask_item *mip;
unsigned int idx;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (debugifc_match_keyword(buf,count,mip->name)) {
return mip->msk;
@@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
unsigned int idx;
int bcnt = 0;
int ccnt;
- for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
mip = mask_items + idx;
if (!(mip->msk & msk)) continue;
ccnt = scnprintf(buf,sz,"%s%c%s",
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
index e0e248b83..bd5feef0e 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -103,9 +103,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
}
msg[1].len = pcnt;
msg[1].buf = eeprom+tcnt;
- if ((ret = i2c_transfer(
- &hdw->i2c_adap,
- msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+ if ((ret = i2c_transfer(&hdw->i2c_adap,
+ msg,ARRAY_SIZE(msg))) != 2) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"eeprom fetch set offs err=%d",ret);
kfree(eeprom);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 707fa1b67..b9ee07638 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -191,25 +191,23 @@ static int pvr2_encoder_cmd(void *ctxt,
*/
- if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many input arguments"
" (was given %u limit %u)",
- arg_cnt_send,
- (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+ arg_cnt_send, ARRAY_SIZE(wrData) - 4);
return -EINVAL;
}
- if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many return arguments"
" (was given %u limit %u)",
- arg_cnt_recv,
- (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+ arg_cnt_recv, ARRAY_SIZE(rdData) - 4);
return -EINVAL;
}
@@ -223,7 +221,7 @@ static int pvr2_encoder_cmd(void *ctxt,
for (idx = 0; idx < arg_cnt_send; idx++) {
wrData[idx+4] = argp[idx];
}
- for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
wrData[idx+4] = 0;
}
@@ -267,8 +265,7 @@ static int pvr2_encoder_cmd(void *ctxt,
if (ret) break;
wrData[0] = 0x7;
ret = pvr2_encoder_read_words(
- hdw,0,rdData,
- sizeof(rdData)/sizeof(rdData[0]));
+ hdw,0,rdData, ARRAY_SIZE(rdData));
if (ret) break;
#if 0
for (idx = 0; idx < args; idx++) {
@@ -302,13 +299,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
unsigned int idx;
u32 data[12];
- if (args > sizeof(data)/sizeof(data[0])) {
+ if (args > ARRAY_SIZE(data)) {
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Failed to write cx23416 command"
" - too many arguments"
" (was given %u limit %u)",
- args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+ args, ARRAY_SIZE(data));
return -EINVAL;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 8ac9c7d7f..47b1365d7 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -142,17 +142,10 @@ struct pvr2_ctrl {
};
-struct pvr2_audio_stat {
- void *ctxt;
- void (*detach)(void *);
- int (*status)(void *);
-};
-
struct pvr2_decoder_ctrl {
void *ctxt;
void (*detach)(void *);
void (*enable)(void *,int);
- int (*tuned)(void *);
void (*force_reset)(void *);
};
@@ -283,6 +276,10 @@ struct pvr2_hdw {
unsigned int freqSelector; /* 0=radio 1=television */
int freqDirty;
+ /* Current tuner info - this information is polled from the I2C bus */
+ struct v4l2_tuner tuner_signal_info;
+ int tuner_signal_stale;
+
/* Video standard handling */
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
@@ -314,11 +311,6 @@ struct pvr2_hdw {
enum pvr2_config config;
- /* Information about what audio signal we're hearing */
- int flag_stereo;
- int flag_bilingual;
- struct pvr2_audio_stat *audio_stat;
-
/* Control state needed for cx2341x module */
struct cx2341x_mpeg_params enc_cur_state;
struct cx2341x_mpeg_params enc_ctl_state;
@@ -343,7 +335,6 @@ struct pvr2_hdw {
VCREATE_DATA(res_hor);
VCREATE_DATA(res_ver);
VCREATE_DATA(srate);
- VCREATE_DATA(automodeswitch);
#undef VCREATE_DATA
struct pvr2_ctld_info *mpeg_ctrl_info;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 0fce806ea..b07bd58ea 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -40,8 +40,6 @@
#define TV_MIN_FREQ 55250000L
#define TV_MAX_FREQ 850000000L
-#define RADIO_MIN_FREQ 87000000L
-#define RADIO_MAX_FREQ 108000000L
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
@@ -77,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
static struct pvr2_string_table pvr2_client_lists[] = {
[PVR2_HDW_TYPE_29XXX] = {
- pvr2_client_29xxx,
- sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- pvr2_client_24xxx,
- sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
},
};
@@ -95,7 +91,6 @@ static int procreload = 0;
static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-static int auto_mode_switch[PVR_NUM];
static int init_pause_msec = 0;
module_param(ctlchg, int, S_IRUGO|S_IWUSR);
@@ -113,8 +108,6 @@ module_param_array(video_std, int, NULL, 0444);
MODULE_PARM_DESC(video_std,"specify initial video standard");
module_param_array(tolerance, int, NULL, 0444);
MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
-module_param_array(auto_mode_switch, int, NULL, 0444);
-MODULE_PARM_DESC(auto_mode_switch,"Enable TV/Radio automatic mode switch based on freq");
#define PVR2_CTL_WRITE_ENDPOINT 0x01
#define PVR2_CTL_READ_ENDPOINT 0x81
@@ -218,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
}
};
-#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
static const char *control_values_srate[] = {
@@ -265,7 +258,6 @@ static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
@@ -437,34 +429,48 @@ static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
cptr->hdw->input_dirty = 0;
}
-static int ctrl_freq_check(struct pvr2_ctrl *cptr,int v)
-{
- /* Both ranges are simultaneously considered legal, in order to
- permit implicit mode switching, i.e. set a frequency in the
- other range and the mode will switch */
- return (((v >= RADIO_MIN_FREQ) && (v <= RADIO_MAX_FREQ)) ||
- ((v >= TV_MIN_FREQ) && (v <= TV_MAX_FREQ)));
-}
static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
{
- /* Actual maximum depends on radio/tv mode */
- if (cptr->hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- *vp = RADIO_MAX_FREQ;
- } else {
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangehigh;
+ if (!fv) {
+ /* Safety fallback */
*vp = TV_MAX_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
}
+ *vp = fv;
return 0;
}
static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
{
- /* Actual minimum depends on radio/tv mode */
- if (cptr->hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- *vp = RADIO_MIN_FREQ;
- } else {
+ unsigned long fv;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ fv = hdw->tuner_signal_info.rangelow;
+ if (!fv) {
+ /* Safety fallback */
*vp = TV_MIN_FREQ;
+ return 0;
+ }
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
+ fv = (fv * 125) / 2;
+ } else {
+ fv = fv * 62500;
}
+ *vp = fv;
return 0;
}
@@ -624,8 +630,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
{
- *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
- PVR2_SIGNAL_OK) ? 1 : 0);
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ *vp = hdw->tuner_signal_info.signal;
+ return 0;
+}
+
+static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int val = 0;
+ unsigned int subchan;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ pvr2_i2c_core_status_poll(hdw);
+ subchan = hdw->tuner_signal_info.rxsubchans;
+ if (subchan & V4L2_TUNER_SUB_MONO) {
+ val |= (1 << V4L2_TUNER_MODE_MONO);
+ }
+ if (subchan & V4L2_TUNER_SUB_STEREO) {
+ val |= (1 << V4L2_TUNER_MODE_STEREO);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG1) {
+ val |= (1 << V4L2_TUNER_MODE_LANG1);
+ }
+ if (subchan & V4L2_TUNER_SUB_LANG2) {
+ val |= (1 << V4L2_TUNER_MODE_LANG2);
+ }
+ *vp = val;
return 0;
}
@@ -694,7 +724,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
#define DEFENUM(tab) \
.type = pvr2_ctl_enum, \
- .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.count = ARRAY_SIZE(tab), \
.def.type_enum.value_names = tab
#define DEFBOOL \
@@ -735,7 +765,6 @@ VCREATE_FUNCS(audiomode)
VCREATE_FUNCS(res_hor)
VCREATE_FUNCS(res_ver)
VCREATE_FUNCS(srate)
-VCREATE_FUNCS(automodeswitch)
/* Table definition of all controls which can be manipulated */
static const struct pvr2_ctl_info control_defs[] = {
@@ -835,12 +864,6 @@ static const struct pvr2_ctl_info control_defs[] = {
.get_max_value = ctrl_vres_max_get,
.get_min_value = ctrl_vres_min_get,
},{
- .desc = "Automatic TV / Radio mode switch based on frequency",
- .name = "auto_mode_switch",
- .default_value = 0,
- DEFREF(automodeswitch),
- DEFBOOL,
- },{
.v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
.default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
.desc = "Audio Sampling Frequency",
@@ -856,10 +879,9 @@ static const struct pvr2_ctl_info control_defs[] = {
.get_value = ctrl_freq_get,
.is_dirty = ctrl_freq_is_dirty,
.clear_dirty = ctrl_freq_clear_dirty,
- DEFINT(TV_MIN_FREQ,TV_MAX_FREQ),
+ DEFINT(0,0),
/* Hook in check for input value (tv/radio) and adjust
max/min values accordingly */
- .check_value = ctrl_freq_check,
.get_max_value = ctrl_freq_max_get,
.get_min_value = ctrl_freq_min_get,
},{
@@ -873,10 +895,9 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "freq_table_value",
.set_value = ctrl_channelfreq_set,
.get_value = ctrl_channelfreq_get,
- DEFINT(TV_MIN_FREQ,TV_MAX_FREQ),
+ DEFINT(0,0),
/* Hook in check for input value (tv/radio) and adjust
max/min values accordingly */
- .check_value = ctrl_freq_check,
.get_max_value = ctrl_freq_max_get,
.get_min_value = ctrl_freq_min_get,
},{
@@ -899,7 +920,20 @@ static const struct pvr2_ctl_info control_defs[] = {
.desc = "Signal Present",
.name = "signal_present",
.get_value = ctrl_signal_get,
- DEFBOOL,
+ DEFINT(0,65535),
+ },{
+ .desc = "Audio Modes Present",
+ .name = "audio_modes_present",
+ .get_value = ctrl_audio_modes_present_get,
+ /* For this type we "borrow" the V4L2_TUNER_MODE enum from
+ v4l. Nothing outside of this module cares about this,
+ but I reuse it in order to also reuse the
+ control_values_audiomode string table. */
+ DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
+ (1 << V4L2_TUNER_MODE_STEREO)|
+ (1 << V4L2_TUNER_MODE_LANG1)|
+ (1 << V4L2_TUNER_MODE_LANG2)),
+ control_values_audiomode),
},{
.desc = "Video Standards Available Mask",
.name = "video_standard_mask_available",
@@ -949,7 +983,7 @@ static const struct pvr2_ctl_info control_defs[] = {
}
};
-#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
const char *pvr2_config_get_name(enum pvr2_config cfg)
@@ -985,71 +1019,28 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
driver-core side effects of this action. */
void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
{
- int mode = 0;
-
- /* If hdw->automodeswitch_val is set, then we do something clever:
- Look at the desired frequency and see if it looks like FM or TV.
- Execute a possible mode switch based on this result. Otherwise
- we use the current input setting to determine which frequency
- register we need to adjust. */
- if (hdw->automodeswitch_val) {
- /* Note that since FM RADIO frequency range sits *inside*
- the TV spectrum that we must therefore check the radio
- range first... */
- if ((val >= RADIO_MIN_FREQ) && (val <= RADIO_MAX_FREQ)) {
- mode = 1;
- } else if ((val >= TV_MIN_FREQ) && (val <= TV_MAX_FREQ)) {
- mode = 2;
- }
- } else {
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- mode = 1;
- } else {
- mode = 2;
- }
- }
-
- switch (mode) {
- case 1:
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
if (hdw->freqSelector) {
/* Swing over to radio frequency selection */
hdw->freqSelector = 0;
hdw->freqDirty = !0;
}
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- /* Force switch to radio mode */
- hdw->input_val = PVR2_CVAL_INPUT_RADIO;
- hdw->input_dirty = !0;
- }
if (hdw->freqValRadio != val) {
hdw->freqValRadio = val;
hdw->freqSlotRadio = 0;
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- hdw->freqDirty = !0;
- }
+ hdw->freqDirty = !0;
}
- break;
- case 2:
+ } else {
if (!(hdw->freqSelector)) {
/* Swing over to television frequency selection */
hdw->freqSelector = 1;
hdw->freqDirty = !0;
}
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- /* Force switch to television mode */
- hdw->input_val = PVR2_CVAL_INPUT_TV;
- hdw->input_dirty = !0;
- }
if (hdw->freqValTelevision != val) {
hdw->freqValTelevision = val;
hdw->freqSlotTelevision = 0;
- if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- hdw->freqDirty = !0;
- }
+ hdw->freqDirty = !0;
}
- break;
- default:
- break;
}
}
@@ -1150,12 +1141,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
};
static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
- fw_files_29xxx,
- sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
},
[PVR2_HDW_TYPE_24XXX] = {
- fw_files_24xxx,
- sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
},
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -1242,8 +1231,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
trace_firmware("pvr2_upload_firmware2");
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
- sizeof(fw_files)/sizeof(fw_files[0]),
- fw_files);
+ ARRAY_SIZE(fw_files), fw_files);
if (ret < 0) return ret;
fwidx = ret;
ret = 0;
@@ -1828,11 +1816,6 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
/* 104.3 MHz, a usable FM station for my area */
hdw->freqValRadio = 104300000L;
- /* Default value for auto mode switch based on module option */
- if ((hdw->unit_number >= 0) && (hdw->unit_number < PVR_NUM)) {
- hdw->automodeswitch_val = auto_mode_switch[hdw->unit_number];
- }
-
// Do not use pvr2_reset_ctl_endpoints() here. It is not
// thread-safe against the normal pvr2_send_request() mechanism.
// (We should make it thread safe).
@@ -1972,26 +1955,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
struct pvr2_ctl_info *ciptr;
hdw_type = devid - pvr2_device_table;
- if (hdw_type >=
- sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"Bogus device type of %u reported",hdw_type);
return NULL;
}
- hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
hdw,pvr2_device_names[hdw_type]);
if (!hdw) goto fail;
- memset(hdw,0,sizeof(*hdw));
+ hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
- hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
GFP_KERNEL);
if (!hdw->controls) goto fail;
- memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
hdw->hdw_type = hdw_type;
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
@@ -2005,11 +1986,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = control_defs+idx;
}
/* Define and configure additional controls from cx2341x module. */
- hdw->mpeg_ctrl_info = kmalloc(
+ hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
if (!hdw->mpeg_ctrl_info) goto fail;
- memset(hdw->mpeg_ctrl_info,0,
- sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
cptr = hdw->controls + idx + CTRLDEF_COUNT;
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
@@ -2206,9 +2185,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
pvr2_stream_destroy(hdw->vid_stream);
hdw->vid_stream = NULL;
}
- if (hdw->audio_stat) {
- hdw->audio_stat->detach(hdw->audio_stat->ctxt);
- }
if (hdw->decoder_ctrl) {
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
}
@@ -2434,10 +2410,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
cptr = hdw->controls + idx;
if (cptr->info->is_dirty == 0) continue;
if (!cptr->info->is_dirty(cptr)) continue;
- if (!commit_flag) {
- commit_flag = !0;
- }
+ commit_flag = !0;
+ if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
cptr->info->name);
value = 0;
@@ -2586,34 +2561,6 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
-{
- unsigned int msk = 0;
- switch (hdw->input_val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_RADIO:
- if (hdw->decoder_ctrl &&
- hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
- msk |= PVR2_SIGNAL_OK;
- if (hdw->audio_stat &&
- hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
- if (hdw->flag_stereo) {
- msk |= PVR2_SIGNAL_STEREO;
- }
- if (hdw->flag_bilingual) {
- msk |= PVR2_SIGNAL_SAP;
- }
- }
- }
- break;
- default:
- msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
- }
- return msk;
-}
-
-
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
{
int result;
@@ -2629,14 +2576,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
}
-/* Return bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+/* Execute poll of tuner status */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_i2c_core_status_poll(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
{
- unsigned int msk = 0;
LOCK_TAKE(hdw->big_lock); do {
- msk = pvr2_hdw_get_signal_status_internal(hdw);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
+ memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
} while (0); LOCK_GIVE(hdw->big_lock);
- return msk;
+ return 0;
}
@@ -2685,14 +2643,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
pvr2_trace(PVR2_TRACE_FIRMWARE,
"Preparing to suck out CPU firmware");
hdw->fw_size = 0x2000;
- hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
if (!hdw->fw_buffer) {
hdw->fw_size = 0;
break;
}
- memset(hdw->fw_buffer,0,hdw->fw_size);
-
/* We have to hold the CPU during firmware upload. */
pvr2_hdw_cpureset_assert(hdw,1);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 8ae874440..ab99bea88 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -45,12 +45,6 @@
#define PVR2_CVAL_INPUT_COMPOSITE 2
#define PVR2_CVAL_INPUT_RADIO 3
-/* Values that pvr2_hdw_get_signal_status() returns */
-#define PVR2_SIGNAL_OK 0x0001
-#define PVR2_SIGNAL_STEREO 0x0002
-#define PVR2_SIGNAL_SAP 0x0004
-
-
/* Subsystem definitions - these are various pieces that can be
independently stopped / started. Usually you don't want to mess with
this directly (let the driver handle things itself), but it is useful
@@ -164,8 +158,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
-/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
-unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+/* Mark tuner status stale so that it will be re-fetched */
+void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
+
+/* Return information about the tuner */
+int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
/* Query device and see if it thinks it is on a high-speed USB link */
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index dbd2466ef..40200c79f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -34,15 +34,17 @@
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
#define OP_STANDARD 0
-#define OP_BCSH 1
-#define OP_VOLUME 2
-#define OP_FREQ 3
-#define OP_AUDIORATE 4
-#define OP_SIZE 5
-#define OP_LOG 6
+#define OP_AUDIOMODE 1
+#define OP_BCSH 2
+#define OP_VOLUME 3
+#define OP_FREQ 4
+#define OP_AUDIORATE 5
+#define OP_SIZE 6
+#define OP_LOG 7
static const struct pvr2_i2c_op * const ops[] = {
[OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+ [OP_AUDIOMODE] = &pvr2_i2c_op_v4l2_audiomode,
[OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
[OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
[OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
@@ -55,11 +57,13 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
int id;
id = cp->client->driver->id;
cp->ctl_mask = ((1 << OP_STANDARD) |
+ (1 << OP_AUDIOMODE) |
(1 << OP_BCSH) |
(1 << OP_VOLUME) |
(1 << OP_FREQ) |
(1 << OP_SIZE) |
(1 << OP_LOG));
+ cp->status_poll = pvr2_v4l2_cmd_status_poll;
if (id == I2C_DRIVERID_MSP3400) {
if (pvr2_i2c_msp3400_setup(hdw,cp)) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 51da8945e..c650e02cc 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -37,6 +37,7 @@ static void set_standard(struct pvr2_hdw *hdw)
vs = hdw->std_mask_cur;
pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
}
+ hdw->tuner_signal_stale = !0;
}
@@ -139,19 +140,50 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
};
+static void set_audiomode(struct pvr2_hdw *hdw)
+{
+ struct v4l2_tuner vt;
+ memset(&vt,0,sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_TUNER,&vt);
+}
+
+
+static int check_audiomode(struct pvr2_hdw *hdw)
+{
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode = {
+ .check = check_audiomode,
+ .update = set_audiomode,
+ .name = "v4l2_audiomode",
+};
+
+
static void set_frequency(struct pvr2_hdw *hdw)
{
unsigned long fv;
struct v4l2_frequency freq;
fv = pvr2_hdw_get_cur_freq(hdw);
pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+ if (hdw->tuner_signal_stale) {
+ pvr2_i2c_core_status_poll(hdw);
+ }
memset(&freq,0,sizeof(freq));
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
// ((fv * 1000) / 62500)
freq.frequency = (fv * 2) / 125;
- freq.type = V4L2_TUNER_RADIO;
} else {
freq.frequency = fv / 62500;
+ }
+ /* tuner-core currently doesn't seem to care about this, but
+ let's set it anyway for completeness. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ freq.type = V4L2_TUNER_RADIO;
+ } else {
freq.type = V4L2_TUNER_ANALOG_TV;
}
freq.tuner = 0;
@@ -230,6 +262,12 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
}
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp)
+{
+ pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info);
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
index 4419e3d43..6c2379fc5 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -32,9 +32,11 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode;
extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *);
#endif /* __PVRUSB2_CMD_V4L2_H */
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 760cb5c7f..4a4f1d64b 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -673,6 +673,33 @@ static int handler_check(struct pvr2_i2c_client *cp)
#define BUFSIZE 500
+
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
+{
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
+ memset(vtp,0,sizeof(*vtp));
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!cp->detected_flag) continue;
+ if (!cp->status_poll) continue;
+ cp->status_poll(cp);
+ }
+ hdw->tuner_signal_stale = 0;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
+ " type=%u strength=%u audio=0x%x cap=0x%x"
+ " low=%u hi=%u",
+ vtp->type,
+ vtp->signal,vtp->rxsubchans,vtp->capability,
+ vtp->rangelow,vtp->rangehigh);
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+
+/* Issue various I2C operations to bring chip-level drivers into sync with
+ state stored in this driver. */
void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
{
unsigned long msk;
@@ -953,12 +980,12 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client)
struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
struct pvr2_i2c_client *cp;
int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
client->name,
client->addr,cp);
if (!cp) return -ENOMEM;
- memset(cp,0,sizeof(*cp));
+ cp->hdw = hdw;
INIT_LIST_HEAD(&cp->list);
cp->client = client;
mutex_lock(&hdw->i2c_list_lock); do {
@@ -1034,8 +1061,7 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
printk("%s: i2c scan beginning\n",hdw->name);
for (i = 0; i < 128; i++) {
msg[0].addr = i;
- rc = i2c_transfer(&hdw->i2c_adap,msg,
- sizeof(msg)/sizeof(msg[0]));
+ rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg));
if (rc != 1) continue;
printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
index 6d7e25247..bd0807b90 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -35,10 +35,12 @@ struct pvr2_i2c_client {
struct i2c_client *client;
struct pvr2_i2c_handler *handler;
struct list_head list;
+ struct pvr2_hdw *hdw;
int detected_flag;
int recv_enable;
unsigned long pend_mask;
unsigned long ctl_mask;
+ void (*status_poll)(struct pvr2_i2c_client *);
};
struct pvr2_i2c_handler {
@@ -67,6 +69,7 @@ int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
void pvr2_i2c_core_sync(struct pvr2_hdw *);
+void pvr2_i2c_core_status_poll(struct pvr2_hdw *);
unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
#define PVR2_I2C_DETAIL_DEBUG 0x0001
#define PVR2_I2C_DETAIL_HANDLER 0x0002
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
index 61c553ddf..ef7293bf1 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -498,9 +498,8 @@ static void buffer_complete(struct urb *urb)
struct pvr2_stream *pvr2_stream_create(void)
{
struct pvr2_stream *sp;
- sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+ sp = kzalloc(sizeof(*sp),GFP_KERNEL);
if (!sp) return sp;
- memset(sp,0,sizeof(*sp));
pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
pvr2_stream_init(sp);
return sp;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index 28385b0c9..c42eef3c2 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -96,10 +96,9 @@ static void pvr2_ioread_done(struct pvr2_ioread *cp)
struct pvr2_ioread *pvr2_ioread_create(void)
{
struct pvr2_ioread *cp;
- cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ cp = kzalloc(sizeof(*cp),GFP_KERNEL);
if (!cp) return NULL;
pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
- memset(cp,0,sizeof(*cp));
if (pvr2_ioread_init(cp) < 0) {
kfree(cp);
return NULL;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
index f95c598ff..4de535498 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -141,10 +141,8 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
cnt = 0;
while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
if (cnt >= bufSize) return 0; // No more characters
- sp = find_std_name(
- std_groups,
- sizeof(std_groups)/sizeof(std_groups[0]),
- bufPtr,cnt);
+ sp = find_std_name(std_groups, ARRAY_SIZE(std_groups),
+ bufPtr,cnt);
if (!sp) return 0; // Illegal color system name
cnt++;
bufPtr += cnt;
@@ -163,8 +161,7 @@ int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
if (ch == '/') break;
cnt++;
}
- sp = find_std_name(std_items,
- sizeof(std_items)/sizeof(std_items[0]),
+ sp = find_std_name(std_items, ARRAY_SIZE(std_items),
bufPtr,cnt);
if (!sp) return 0; // Illegal modulation system ID
t = sp->id & cmsk;
@@ -189,14 +186,10 @@ unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
unsigned int c1,c2;
cfl = 0;
c1 = 0;
- for (idx1 = 0;
- idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
- idx1++) {
+ for (idx1 = 0; idx1 < ARRAY_SIZE(std_groups); idx1++) {
gp = std_groups + idx1;
gfl = 0;
- for (idx2 = 0;
- idx2 < sizeof(std_items)/sizeof(std_items[0]);
- idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_items); idx2++) {
ip = std_items + idx2;
if (!(gp->id & ip->id & id)) continue;
if (!gfl) {
@@ -279,7 +272,7 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+#define generic_standards_cnt ARRAY_SIZE(generic_standards)
static struct v4l2_standard *match_std(v4l2_std_id id)
{
@@ -348,7 +341,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
fmsk |= idmsk;
}
- for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ for (idx2 = 0; idx2 < ARRAY_SIZE(std_mixes); idx2++) {
if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
}
@@ -366,16 +359,15 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
std_cnt);
if (!std_cnt) return NULL; // paranoia
- stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
GFP_KERNEL);
- memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
idx = 0;
/* Enumerate potential special cases */
- for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
- (idx < std_cnt)); idx2++) {
+ for (idx2 = 0; (idx2 < ARRAY_SIZE(std_mixes)) && (idx < std_cnt);
+ idx2++) {
if (!(id & std_mixes[idx2])) continue;
if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 45add19b9..4e3dd17dc 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -494,7 +494,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
unsigned int cnt,acnt;
int ret;
- if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+ if ((ctl_id < 0) || (ctl_id >= ARRAY_SIZE(funcs))) {
return;
}
@@ -502,9 +502,8 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
if (!cptr) return;
- cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+ cip = kzalloc(sizeof(*cip),GFP_KERNEL);
if (!cip) return;
- memset(cip,0,sizeof(*cip));
pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
cip->cptr = cptr;
@@ -614,9 +613,8 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
struct pvr2_sysfs_debugifc *dip;
int ret;
- dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+ dip = kzalloc(sizeof(*dip),GFP_KERNEL);
if (!dip) return;
- memset(dip,0,sizeof(*dip));
dip->attr_debugcmd.attr.owner = THIS_MODULE;
dip->attr_debugcmd.attr.name = "debugcmd";
dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
@@ -769,9 +767,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
if (!usb_dev) return;
- class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+ class_dev = kzalloc(sizeof(*class_dev),GFP_KERNEL);
if (!class_dev) return;
- memset(class_dev,0,sizeof(*class_dev));
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
@@ -863,9 +860,8 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
struct pvr2_sysfs_class *class_ptr)
{
struct pvr2_sysfs *sfp;
- sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+ sfp = kzalloc(sizeof(*sfp),GFP_KERNEL);
if (!sfp) return sfp;
- memset(sfp,0,sizeof(*sfp));
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
pvr2_channel_init(&sfp->channel,mp);
sfp->channel.check_func = pvr2_sysfs_internal_check;
@@ -886,9 +882,8 @@ static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
{
struct pvr2_sysfs_class *clp;
- clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+ clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- memset(clp,0,sizeof(*clp));
pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
index e196d92a6..e234cd3c9 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -94,9 +94,8 @@ int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
struct pvr2_tuner_handler *ctxt;
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->i2c_handler.func_data = ctxt;
ctxt->i2c_handler.func_table = &tuner_funcs;
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 5acb67286..13dc436f6 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -96,40 +96,6 @@ static struct v4l2_capability pvr_capability ={
.reserved = {0,0,0,0}
};
-static struct v4l2_tuner pvr_v4l2_tuners[]= {
- {
- .index = 0,
- .name = "TV Tuner",
- .type = V4L2_TUNER_ANALOG_TV,
- .capability = (V4L2_TUNER_CAP_NORM |
- V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 |
- V4L2_TUNER_CAP_LANG2),
- .rangelow = 0,
- .rangehigh = 0,
- .rxsubchans = V4L2_TUNER_SUB_STEREO,
- .audmode = V4L2_TUNER_MODE_STEREO,
- .signal = 0,
- .afc = 0,
- .reserved = {0,0,0,0}
- }
-#if 0
- {
- .index = 1,
- .name = "Radio Tuner",
- .type = V4L2_TUNER_RADIO,
- .capability = (V4L2_TUNER_CAP_STEREO),
- .rangelow = 0,
- .rangehigh = 0,
- .rxsubchans = 0,
- .audmode = V4L2_TUNER_MODE_STEREO,
- .signal = 0,
- .afc = 0,
- .reserved = {0,0,0,0}
- }
-#endif
-};
-
static struct v4l2_fmtdesc pvr_fmtdesc [] = {
{
.index = 0,
@@ -356,13 +322,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_ENUMAUDIO:
{
+ /* pkt: FIXME: We are returning one "fake" input here
+ which could very well be called "whatever_we_like".
+ This is for apps that want to see an audio input
+ just to feel comfortable, as well as to test if
+ it can do stereo or sth. There is actually no guarantee
+ that the actual audio input cannot change behind the app's
+ back, but most applications should not mind that either.
+
+ Hopefully, mplayer people will work with us on this (this
+ whole mess is to support mplayer pvr://), or Hans will come
+ up with a more standard way to say "we have inputs but we
+ don 't want you to change them independent of video" which
+ will sort this mess.
+ */
+ struct v4l2_audio *vin = arg;
ret = -EINVAL;
+ if (vin->index > 0) break;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
+ break;
break;
}
case VIDIOC_G_AUDIO:
{
- ret = -EINVAL;
+ /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+ struct v4l2_audio *vin = arg;
+ memset(vin,0,sizeof(*vin));
+ vin->index = 0;
+ strncpy(vin->name, "PVRUSB2 Audio",14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ ret = 0;
break;
}
@@ -374,34 +366,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_TUNER:
{
struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
- unsigned int status_mask;
- int val;
- if (vt->index !=0) break;
-
- status_mask = pvr2_hdw_get_signal_status(hdw);
-
- memcpy(vt, &pvr_v4l2_tuners[vt->index],
- sizeof(struct v4l2_tuner));
-
- vt->signal = 0;
- if (status_mask & PVR2_SIGNAL_OK) {
- if (status_mask & PVR2_SIGNAL_STEREO) {
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- } else {
- vt->rxsubchans = V4L2_TUNER_SUB_MONO;
- }
- if (status_mask & PVR2_SIGNAL_SAP) {
- vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
- V4L2_TUNER_SUB_LANG2);
- }
- vt->signal = 65535;
- }
-
- val = 0;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
- &val);
- vt->audmode = val;
+ pvr2_hdw_execute_tuner_poll(hdw);
+ ret = pvr2_hdw_get_tuner_status(hdw,vt);
break;
}
@@ -415,14 +381,34 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
vt->audmode);
+ break;
}
case VIDIOC_S_FREQUENCY:
{
const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
unsigned long fv;
- fv = vf->frequency;
+ struct v4l2_tuner vt;
+ int cur_input;
+ struct pvr2_ctrl *ctrlp;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
+ ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
+ if (ret != 0) break;
if (vf->type == V4L2_TUNER_RADIO) {
+ if (cur_input != PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_RADIO);
+ }
+ } else {
+ if (cur_input == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(ctrlp,
+ PVR2_CVAL_INPUT_TV);
+ }
+ }
+ fv = vf->frequency;
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
fv = (fv * 125) / 2;
} else {
fv = fv * 62500;
@@ -436,7 +422,10 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
int val = 0;
- int cur_input = PVR2_CVAL_INPUT_TV;
+ int cur_input;
+ struct v4l2_tuner vt;
+ ret = pvr2_hdw_get_tuner_status(hdw,&vt);
+ if (ret != 0) break;
ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
&val);
@@ -445,14 +434,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
&cur_input);
if (cur_input == PVR2_CVAL_INPUT_RADIO) {
- val = (val * 2) / 125;
- vf->frequency = val;
vf->type = V4L2_TUNER_RADIO;
} else {
- val /= 62500;
- vf->frequency = val;
vf->type = V4L2_TUNER_ANALOG_TV;
}
+ if (vt.capability & V4L2_TUNER_CAP_LOW) {
+ val = (val * 2) / 125;
+ } else {
+ val /= 62500;
+ }
+ vf->frequency = val;
break;
}
@@ -508,7 +499,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- int lmin,lmax;
+ int lmin,lmax,ldef;
struct pvr2_ctrl *hcp,*vcp;
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
@@ -517,14 +508,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
lmin = pvr2_ctrl_get_min(hcp);
lmax = pvr2_ctrl_get_max(hcp);
- if (w < lmin) {
+ ldef = pvr2_ctrl_get_def(hcp);
+ if (w == -1) {
+ w = ldef;
+ } else if (w < lmin) {
w = lmin;
} else if (w > lmax) {
w = lmax;
}
lmin = pvr2_ctrl_get_min(vcp);
lmax = pvr2_ctrl_get_max(vcp);
- if (h < lmin) {
+ ldef = pvr2_ctrl_get_def(vcp);
+ if (h == -1) {
+ h = ldef;
+ } else if (h < lmin) {
h = lmin;
} else if (h > lmax) {
h = lmax;
@@ -672,6 +669,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_ext_control *ctrl;
unsigned int idx;
int val;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_get_value(
@@ -694,6 +692,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
(struct v4l2_ext_controls *)arg;
struct v4l2_ext_control *ctrl;
unsigned int idx;
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
ret = pvr2_ctrl_set_value(
@@ -716,6 +715,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
unsigned int idx;
/* For the moment just validate that the requested control
actually exists. */
+ ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
@@ -930,11 +930,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
return -EIO;
}
- fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+ fhp = kzalloc(sizeof(*fhp),GFP_KERNEL);
if (!fhp) {
return -ENOMEM;
}
- memset(fhp,0,sizeof(*fhp));
init_waitqueue_head(&fhp->wait_data);
fhp->dev_info = dip;
@@ -1166,7 +1165,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
nr_ptr = vbi_nr;
break;
case VFL_TYPE_RADIO:
- dip->config = pvr2_config_pcm;
+ dip->stream = &vp->channel.mc_head->video_stream;
+ dip->config = pvr2_config_mpeg;
dip->minor_type = pvr2_v4l_type_radio;
nr_ptr = radio_nr;
break;
@@ -1178,13 +1178,6 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
}
memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
-#if 0
- /* ????? This relation may be problematic on a disconnect. Is this
- really needed? I can't seem to find a reason for it. This
- can't be a required thing - what if the video device being set
- up doesn't have a real hardware device under it? */
- dip->vdev->dev = &usbdev->dev;
-#endif
dip->devbase.release = pvr2_video_device_release;
mindevnum = -1;
@@ -1212,19 +1205,16 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
- vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
- memset(vp,0,sizeof(*vp));
- vp->dev_video = kmalloc(sizeof(*vp->dev_video),GFP_KERNEL);
- vp->dev_radio = kmalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
if (!(vp->dev_video && vp->dev_radio)) {
- if (vp->dev_video) kfree(vp->dev_video);
- if (vp->dev_radio) kfree(vp->dev_radio);
+ kfree(vp->dev_video);
+ kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
- memset(vp->dev_video,0,sizeof(*vp->dev_video));
- memset(vp->dev_radio,0,sizeof(*vp->dev_radio));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
index 05f2cddeb..df042509a 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -66,7 +66,9 @@ static void set_input(struct pvr2_v4l_decoder *ctxt)
route.input = SAA7115_SVIDEO2;
break;
case PVR2_CVAL_INPUT_RADIO:
- // ????? No idea yet what to do here
+ // In radio mode, we mute the video, but point at one
+ // spot just to stay consistent
+ route.input = SAA7115_COMPOSITE5;
default:
return;
}
@@ -137,8 +139,7 @@ static int decoder_check(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (decoder_ops[idx].check(ctxt)) {
@@ -154,8 +155,7 @@ static void decoder_update(struct pvr2_v4l_decoder *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -183,18 +183,6 @@ static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
}
-static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
-{
- struct v4l2_tuner vt;
- int ret;
-
- memset(&vt,0,sizeof(vt));
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
- if (ret < 0) return -EINVAL;
- return vt.signal ? 1 : 0;
-}
-
-
static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
{
return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
@@ -218,20 +206,17 @@ int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
if (cp->handler) return 0;
if (!decoder_detect(cp)) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->ctrl.ctxt = ctxt;
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
- ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
- sizeof(decoder_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
hdw->decoder_ctrl = &ctxt->ctrl;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
index ce08dee9b..7890b45d2 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -105,8 +105,7 @@ static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (ctxt->stale_mask & msk) continue;
if (wm8775_ops[idx].check(ctxt)) {
@@ -122,8 +121,7 @@ static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
unsigned long msk;
unsigned int idx;
- for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
- idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(wm8775_ops); idx++) {
msk = 1 << idx;
if (!(ctxt->stale_mask & msk)) continue;
ctxt->stale_mask &= ~msk;
@@ -146,16 +144,14 @@ int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
if (cp->handler) return 0;
- ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
if (!ctxt) return 0;
- memset(ctxt,0,sizeof(*ctxt));
ctxt->handler.func_data = ctxt;
ctxt->handler.func_table = &hfuncs;
ctxt->client = cp;
ctxt->hdw = hdw;
- ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
- sizeof(wm8775_ops[0]))) - 1;
+ ctxt->stale_mask = (1 << ARRAY_SIZE(wm8775_ops)) - 1;
cp->handler = &ctxt->handler;
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
cp->client->addr);
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_pas202bca.c b/linux/drivers/media/video/sn9c102/sn9c102_pas202bca.c
deleted file mode 100644
index c8f1ae215..000000000
--- a/linux/drivers/media/video/sn9c102/sn9c102_pas202bca.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
- * Controllers *
- * *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "sn9c102_sensor.h"
-
-
-static struct sn9c102_sensor pas202bca;
-
-
-static int pas202bca_init(struct sn9c102_device* cam)
-{
- int err = 0;
-
- err += sn9c102_write_reg(cam, 0x00, 0x10);
- err += sn9c102_write_reg(cam, 0x00, 0x11);
- err += sn9c102_write_reg(cam, 0x00, 0x14);
- err += sn9c102_write_reg(cam, 0x20, 0x17);
- err += sn9c102_write_reg(cam, 0x30, 0x19);
- err += sn9c102_write_reg(cam, 0x09, 0x18);
-
- err += sn9c102_i2c_write(cam, 0x02, 0x14);
- err += sn9c102_i2c_write(cam, 0x03, 0x40);
- err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
- err += sn9c102_i2c_write(cam, 0x0e, 0x01);
- err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
- err += sn9c102_i2c_write(cam, 0x10, 0x08);
- err += sn9c102_i2c_write(cam, 0x13, 0x63);
- err += sn9c102_i2c_write(cam, 0x15, 0x70);
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- msleep(400);
-
- return err;
-}
-
-
-static int pas202bca_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
-{
- int err = 0;
-
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x24, 0x17);
- else
- err += sn9c102_write_reg(cam, 0x20, 0x17);
-
- return err;
-}
-
-
-static int pas202bca_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
- break;
- case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
- break;
- case SN9C102_V4L2_CID_DAC_MAGNITUDE:
- err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += sn9c102_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static int pas202bca_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
-{
- struct sn9c102_sensor* s = &pas202bca;
- int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
-
- err += sn9c102_write_reg(cam, h_start, 0x12);
- err += sn9c102_write_reg(cam, v_start, 0x13);
-
- return err;
-}
-
-
-static struct sn9c102_sensor pas202bca = {
- .name = "PAS202BCA",
- .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
- .frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
- .interface = SN9C102_I2C_2WIRES,
- .i2c_slave_id = 0x40,
- .init = &pas202bca_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = 0,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0c,
- .flags = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = 0,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = 0,
- },
- {
- .id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x04,
- .flags = 0,
- },
- },
- .set_ctrl = &pas202bca_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .set_crop = &pas202bca_set_crop,
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
- .set_pix_format = &pas202bca_set_pix_format
-};
-
-
-int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
-{
- const struct usb_device_id pas202bca_id_table[] = {
- { USB_DEVICE(0x0c45, 0x60af), },
- { }
- };
- int err = 0;
-
- if (!sn9c102_match_id(cam,pas202bca_id_table))
- return -ENODEV;
-
- err += sn9c102_write_reg(cam, 0x01, 0x01);
- err += sn9c102_write_reg(cam, 0x40, 0x01);
- err += sn9c102_write_reg(cam, 0x28, 0x17);
- if (err)
- return -EIO;
-
- if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
- return -ENODEV;
-
- sn9c102_attach_sensor(cam, &pas202bca);
-
- return 0;
-}
diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c
index 155c9a75a..ddedd7fbb 100644
--- a/linux/drivers/media/video/vivi.c
+++ b/linux/drivers/media/video/vivi.c
@@ -610,6 +610,7 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
dma_q->kthread = NULL;
dma_q->notify = &sem;
+ dma_q->rmmod = 0;
if (kernel_thread(vivi_thread, dma_q, 0) < 0) {
printk (KERN_ERR "sdim: kernel_thread() failed\n");