V4L/DVB (10271): saa7146: convert to video_ioctl2.
The conversion to video_ioctl2 is the first phase to converting this driver to the latest v4l2 framework. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
c9b8b04b26
commit
b960074fec
@@ -308,14 +308,6 @@ static int fops_release(struct file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg));
|
|
||||||
*/
|
|
||||||
return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
|
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
|
||||||
{
|
{
|
||||||
struct saa7146_fh *fh = file->private_data;
|
struct saa7146_fh *fh = file->private_data;
|
||||||
@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops =
|
|||||||
.write = fops_write,
|
.write = fops_write,
|
||||||
.poll = fops_poll,
|
.poll = fops_poll,
|
||||||
.mmap = fops_mmap,
|
.mmap = fops_mmap,
|
||||||
.ioctl = fops_ioctl,
|
.ioctl = video_ioctl2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
|
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
|
||||||
@@ -452,19 +444,16 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct video_device device_template =
|
|
||||||
{
|
|
||||||
.fops = &video_fops,
|
|
||||||
.minor = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
|
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
|
||||||
{
|
{
|
||||||
struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL);
|
struct saa7146_vv *vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
|
||||||
if( NULL == vv ) {
|
|
||||||
|
if (vv == NULL) {
|
||||||
ERR(("out of memory. aborting.\n"));
|
ERR(("out of memory. aborting.\n"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
ext_vv->ops = saa7146_video_ioctl_ops;
|
||||||
|
ext_vv->core_ops = &saa7146_video_ioctl_ops;
|
||||||
|
|
||||||
DEB_EE(("dev:%p\n",dev));
|
DEB_EE(("dev:%p\n",dev));
|
||||||
|
|
||||||
@@ -521,6 +510,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
|
|||||||
{
|
{
|
||||||
struct saa7146_vv *vv = dev->vv_data;
|
struct saa7146_vv *vv = dev->vv_data;
|
||||||
struct video_device *vfd;
|
struct video_device *vfd;
|
||||||
|
int err;
|
||||||
|
|
||||||
DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
|
DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type));
|
||||||
|
|
||||||
@@ -529,16 +519,18 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
|
|||||||
if (vfd == NULL)
|
if (vfd == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
memcpy(vfd, &device_template, sizeof(struct video_device));
|
vfd->fops = &video_fops;
|
||||||
strlcpy(vfd->name, name, sizeof(vfd->name));
|
vfd->ioctl_ops = dev->ext_vv_data ? &dev->ext_vv_data->ops :
|
||||||
|
&saa7146_video_ioctl_ops;
|
||||||
vfd->release = video_device_release;
|
vfd->release = video_device_release;
|
||||||
|
strlcpy(vfd->name, name, sizeof(vfd->name));
|
||||||
video_set_drvdata(vfd, dev);
|
video_set_drvdata(vfd, dev);
|
||||||
|
|
||||||
// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
|
err = video_register_device(vfd, type, -1);
|
||||||
if (video_register_device(vfd, type, -1) < 0) {
|
if (err < 0) {
|
||||||
ERR(("cannot register v4l2 device. skipping.\n"));
|
ERR(("cannot register v4l2 device. skipping.\n"));
|
||||||
video_device_release(vfd);
|
video_device_release(vfd);
|
||||||
return -1;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( VFL_TYPE_GRABBER == type ) {
|
if( VFL_TYPE_GRABBER == type ) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -316,253 +316,260 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
|
||||||
{
|
{
|
||||||
struct saa7146_dev *dev = fh->dev;
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
dprintk(4, "saa7146_dev: %p\n", dev);
|
u16 stereo_det;
|
||||||
|
s8 stereo;
|
||||||
|
|
||||||
switch (cmd) {
|
dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
|
||||||
case VIDIOC_G_TUNER:
|
|
||||||
{
|
|
||||||
struct v4l2_tuner *t = arg;
|
|
||||||
u16 stereo_det;
|
|
||||||
s8 stereo;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index);
|
if (!av7110->analog_tuner_flags || t->index != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
if (!av7110->analog_tuner_flags || t->index != 0)
|
memset(t, 0, sizeof(*t));
|
||||||
return -EINVAL;
|
strcpy((char *)t->name, "Television");
|
||||||
|
|
||||||
memset(t, 0, sizeof(*t));
|
t->type = V4L2_TUNER_ANALOG_TV;
|
||||||
strcpy((char *)t->name, "Television");
|
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
|
||||||
|
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
||||||
|
t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
|
||||||
|
t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
|
||||||
|
/* FIXME: add the real signal strength here */
|
||||||
|
t->signal = 0xffff;
|
||||||
|
t->afc = 0;
|
||||||
|
|
||||||
t->type = V4L2_TUNER_ANALOG_TV;
|
/* FIXME: standard / stereo detection is still broken */
|
||||||
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
|
msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
|
||||||
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
|
||||||
t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */
|
msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
|
||||||
t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */
|
dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
|
||||||
/* FIXME: add the real signal strength here */
|
stereo = (s8)(stereo_det >> 8);
|
||||||
t->signal = 0xffff;
|
if (stereo > 0x10) {
|
||||||
t->afc = 0;
|
/* stereo */
|
||||||
|
t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
|
||||||
|
t->audmode = V4L2_TUNER_MODE_STEREO;
|
||||||
|
} else if (stereo < -0x10) {
|
||||||
|
/* bilingual */
|
||||||
|
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
||||||
|
t->audmode = V4L2_TUNER_MODE_LANG1;
|
||||||
|
} else /* mono */
|
||||||
|
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||||
|
|
||||||
// FIXME: standard / stereo detection is still broken
|
return 0;
|
||||||
msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det);
|
}
|
||||||
dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det);
|
|
||||||
msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det);
|
|
||||||
dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det);
|
|
||||||
stereo = (s8)(stereo_det >> 8);
|
|
||||||
if (stereo > 0x10) {
|
|
||||||
/* stereo */
|
|
||||||
t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
|
|
||||||
t->audmode = V4L2_TUNER_MODE_STEREO;
|
|
||||||
}
|
|
||||||
else if (stereo < -0x10) {
|
|
||||||
/* bilingual */
|
|
||||||
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
|
||||||
t->audmode = V4L2_TUNER_MODE_LANG1;
|
|
||||||
}
|
|
||||||
else /* mono */
|
|
||||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
|
||||||
|
|
||||||
return 0;
|
static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
|
||||||
}
|
{
|
||||||
case VIDIOC_S_TUNER:
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
{
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
struct v4l2_tuner *t = arg;
|
u16 fm_matrix, src;
|
||||||
u16 fm_matrix, src;
|
dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
|
||||||
dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
|
|
||||||
|
|
||||||
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
switch (t->audmode) {
|
switch (t->audmode) {
|
||||||
case V4L2_TUNER_MODE_STEREO:
|
case V4L2_TUNER_MODE_STEREO:
|
||||||
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
|
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
|
||||||
fm_matrix = 0x3001; // stereo
|
fm_matrix = 0x3001; /* stereo */
|
||||||
src = 0x0020;
|
src = 0x0020;
|
||||||
break;
|
break;
|
||||||
case V4L2_TUNER_MODE_LANG1_LANG2:
|
case V4L2_TUNER_MODE_LANG1_LANG2:
|
||||||
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
|
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
|
||||||
fm_matrix = 0x3000; // bilingual
|
fm_matrix = 0x3000; /* bilingual */
|
||||||
src = 0x0020;
|
src = 0x0020;
|
||||||
break;
|
break;
|
||||||
case V4L2_TUNER_MODE_LANG1:
|
case V4L2_TUNER_MODE_LANG1:
|
||||||
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
|
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
|
||||||
fm_matrix = 0x3000; // mono
|
fm_matrix = 0x3000; /* mono */
|
||||||
src = 0x0000;
|
src = 0x0000;
|
||||||
break;
|
break;
|
||||||
case V4L2_TUNER_MODE_LANG2:
|
case V4L2_TUNER_MODE_LANG2:
|
||||||
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
|
dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
|
||||||
fm_matrix = 0x3000; // mono
|
fm_matrix = 0x3000; /* mono */
|
||||||
src = 0x0010;
|
src = 0x0010;
|
||||||
break;
|
break;
|
||||||
default: /* case V4L2_TUNER_MODE_MONO: */
|
default: /* case V4L2_TUNER_MODE_MONO: */
|
||||||
dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
|
dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
|
||||||
fm_matrix = 0x3000; // mono
|
fm_matrix = 0x3000; /* mono */
|
||||||
src = 0x0030;
|
src = 0x0030;
|
||||||
break;
|
|
||||||
}
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_FREQUENCY:
|
|
||||||
{
|
|
||||||
struct v4l2_frequency *f = arg;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
|
|
||||||
|
|
||||||
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
memset(f, 0, sizeof(*f));
|
|
||||||
f->type = V4L2_TUNER_ANALOG_TV;
|
|
||||||
f->frequency = av7110->current_freq;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_FREQUENCY:
|
|
||||||
{
|
|
||||||
struct v4l2_frequency *f = arg;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
|
|
||||||
|
|
||||||
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (V4L2_TUNER_ANALOG_TV != f->type)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
|
|
||||||
|
|
||||||
/* tune in desired frequency */
|
|
||||||
if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
|
|
||||||
ves1820_set_tv_freq(dev, f->frequency);
|
|
||||||
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
|
|
||||||
stv0297_set_tv_freq(dev, f->frequency);
|
|
||||||
}
|
|
||||||
av7110->current_freq = f->frequency;
|
|
||||||
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone
|
|
||||||
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_ENUMINPUT:
|
|
||||||
{
|
|
||||||
struct v4l2_input *i = arg;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
|
|
||||||
|
|
||||||
if (av7110->analog_tuner_flags) {
|
|
||||||
if (i->index < 0 || i->index >= 4)
|
|
||||||
return -EINVAL;
|
|
||||||
} else {
|
|
||||||
if (i->index != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_INPUT:
|
|
||||||
{
|
|
||||||
int *input = (int *)arg;
|
|
||||||
*input = av7110->current_input;
|
|
||||||
dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_INPUT:
|
|
||||||
{
|
|
||||||
int input = *(int *)arg;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
|
|
||||||
|
|
||||||
if (!av7110->analog_tuner_flags)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (input < 0 || input >= 4)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
av7110->current_input = input;
|
|
||||||
return av7110_dvb_c_switch(fh);
|
|
||||||
}
|
|
||||||
case VIDIOC_G_AUDIO:
|
|
||||||
{
|
|
||||||
struct v4l2_audio *a = arg;
|
|
||||||
|
|
||||||
dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
|
|
||||||
if (a->index != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VIDIOC_S_AUDIO:
|
msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix);
|
||||||
{
|
msp_writereg(av7110, MSP_WR_DSP, 0x0008, src);
|
||||||
struct v4l2_audio *a = arg;
|
msp_writereg(av7110, MSP_WR_DSP, 0x0009, src);
|
||||||
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
|
msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
|
||||||
break;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency);
|
||||||
|
|
||||||
|
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memset(f, 0, sizeof(*f));
|
||||||
|
f->type = V4L2_TUNER_ANALOG_TV;
|
||||||
|
f->frequency = av7110->current_freq;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency);
|
||||||
|
|
||||||
|
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (V4L2_TUNER_ANALOG_TV != f->type)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);
|
||||||
|
|
||||||
|
/* tune in desired frequency */
|
||||||
|
if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
|
||||||
|
ves1820_set_tv_freq(dev, f->frequency);
|
||||||
|
else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297)
|
||||||
|
stv0297_set_tv_freq(dev, f->frequency);
|
||||||
|
av7110->current_freq = f->frequency;
|
||||||
|
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000);
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */
|
||||||
|
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
|
||||||
|
|
||||||
|
if (av7110->analog_tuner_flags) {
|
||||||
|
if (i->index < 0 || i->index >= 4)
|
||||||
|
return -EINVAL;
|
||||||
|
} else {
|
||||||
|
if (i->index != 0)
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
case VIDIOC_G_SLICED_VBI_CAP:
|
|
||||||
{
|
memcpy(i, &inputs[i->index], sizeof(struct v4l2_input));
|
||||||
struct v4l2_sliced_vbi_cap *cap = arg;
|
|
||||||
dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
|
return 0;
|
||||||
memset(cap, 0, sizeof *cap);
|
}
|
||||||
if (FW_VERSION(av7110->arm_app) >= 0x2623) {
|
|
||||||
cap->service_set = V4L2_SLICED_WSS_625;
|
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
|
||||||
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
|
{
|
||||||
}
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
break;
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
*input = av7110->current_input;
|
||||||
|
dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
|
||||||
|
|
||||||
|
if (!av7110->analog_tuner_flags)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (input < 0 || input >= 4)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
av7110->current_input = input;
|
||||||
|
return av7110_dvb_c_switch(fh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
|
||||||
|
{
|
||||||
|
dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
|
||||||
|
if (a->index != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
|
||||||
|
{
|
||||||
|
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
|
||||||
|
struct v4l2_sliced_vbi_cap *cap)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n");
|
||||||
|
memset(cap, 0, sizeof(*cap));
|
||||||
|
if (FW_VERSION(av7110->arm_app) >= 0x2623) {
|
||||||
|
cap->service_set = V4L2_SLICED_WSS_625;
|
||||||
|
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
|
||||||
}
|
}
|
||||||
case VIDIOC_G_FMT:
|
return 0;
|
||||||
{
|
}
|
||||||
struct v4l2_format *f = arg;
|
|
||||||
dprintk(2, "VIDIOC_G_FMT:\n");
|
static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
|
||||||
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
|
struct v4l2_format *f)
|
||||||
FW_VERSION(av7110->arm_app) < 0x2623)
|
{
|
||||||
return -EAGAIN; /* handled by core driver */
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
if (av7110->wssMode) {
|
|
||||||
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
|
dprintk(2, "VIDIOC_G_FMT:\n");
|
||||||
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
|
if (FW_VERSION(av7110->arm_app) < 0x2623)
|
||||||
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
|
return -EINVAL;
|
||||||
}
|
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
|
||||||
break;
|
if (av7110->wssMode) {
|
||||||
|
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
|
||||||
|
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
|
||||||
|
f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
|
||||||
}
|
}
|
||||||
case VIDIOC_S_FMT:
|
return 0;
|
||||||
{
|
}
|
||||||
struct v4l2_format *f = arg;
|
|
||||||
dprintk(2, "VIDIOC_S_FMT\n");
|
static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
|
||||||
if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
|
struct v4l2_format *f)
|
||||||
FW_VERSION(av7110->arm_app) < 0x2623)
|
{
|
||||||
return -EAGAIN; /* handled by core driver */
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
|
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
|
||||||
f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
|
|
||||||
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
|
dprintk(2, "VIDIOC_S_FMT\n");
|
||||||
/* WSS controlled by firmware */
|
if (FW_VERSION(av7110->arm_app) < 0x2623)
|
||||||
av7110->wssMode = 0;
|
return -EINVAL;
|
||||||
av7110->wssData = 0;
|
if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
|
||||||
return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
|
f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
|
||||||
SetWSSConfig, 1, 0);
|
memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
|
||||||
} else {
|
/* WSS controlled by firmware */
|
||||||
memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
|
av7110->wssMode = 0;
|
||||||
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
|
av7110->wssData = 0;
|
||||||
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
|
return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
|
||||||
f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data);
|
SetWSSConfig, 1, 0);
|
||||||
/* WSS controlled by userspace */
|
} else {
|
||||||
av7110->wssMode = 1;
|
memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
|
||||||
av7110->wssData = 0;
|
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
|
||||||
}
|
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
|
||||||
break;
|
f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data);
|
||||||
}
|
/* WSS controlled by userspace */
|
||||||
default:
|
av7110->wssMode = 1;
|
||||||
printk("no such ioctl\n");
|
av7110->wssData = 0;
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -609,22 +616,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
|
|||||||
* INITIALIZATION
|
* INITIALIZATION
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static struct saa7146_extension_ioctls ioctls[] = {
|
|
||||||
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_FMT, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_S_FMT, SAA7146_BEFORE },
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
static u8 saa7113_init_regs[] = {
|
static u8 saa7113_init_regs[] = {
|
||||||
0x02, 0xd0,
|
0x02, 0xd0,
|
||||||
0x03, 0x23,
|
0x03, 0x23,
|
||||||
@@ -788,20 +779,34 @@ int av7110_init_analog_module(struct av7110 *av7110)
|
|||||||
int av7110_init_v4l(struct av7110 *av7110)
|
int av7110_init_v4l(struct av7110 *av7110)
|
||||||
{
|
{
|
||||||
struct saa7146_dev* dev = av7110->dev;
|
struct saa7146_dev* dev = av7110->dev;
|
||||||
|
struct saa7146_ext_vv *vv_data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* special case DVB-C: these cards have an analog tuner
|
/* special case DVB-C: these cards have an analog tuner
|
||||||
plus need some special handling, so we have separate
|
plus need some special handling, so we have separate
|
||||||
saa7146_ext_vv data for these... */
|
saa7146_ext_vv data for these... */
|
||||||
if (av7110->analog_tuner_flags)
|
if (av7110->analog_tuner_flags)
|
||||||
ret = saa7146_vv_init(dev, &av7110_vv_data_c);
|
vv_data = &av7110_vv_data_c;
|
||||||
else
|
else
|
||||||
ret = saa7146_vv_init(dev, &av7110_vv_data_st);
|
vv_data = &av7110_vv_data_st;
|
||||||
|
ret = saa7146_vv_init(dev, vv_data);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ERR(("cannot init capture device. skipping.\n"));
|
ERR(("cannot init capture device. skipping.\n"));
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
vv_data->ops.vidioc_enum_input = vidioc_enum_input;
|
||||||
|
vv_data->ops.vidioc_g_input = vidioc_g_input;
|
||||||
|
vv_data->ops.vidioc_s_input = vidioc_s_input;
|
||||||
|
vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
|
||||||
|
vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
|
||||||
|
vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
|
||||||
|
vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
|
||||||
|
vv_data->ops.vidioc_g_audio = vidioc_g_audio;
|
||||||
|
vv_data->ops.vidioc_s_audio = vidioc_s_audio;
|
||||||
|
vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
|
||||||
|
vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
|
||||||
|
vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
|
||||||
|
|
||||||
if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
|
if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
|
||||||
ERR(("cannot register capture device. skipping.\n"));
|
ERR(("cannot register capture device. skipping.\n"));
|
||||||
@@ -900,9 +905,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
|
|||||||
.num_stds = ARRAY_SIZE(standard),
|
.num_stds = ARRAY_SIZE(standard),
|
||||||
.std_callback = &std_callback,
|
.std_callback = &std_callback,
|
||||||
|
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = av7110_ioctl,
|
|
||||||
|
|
||||||
.vbi_fops.open = av7110_vbi_reset,
|
.vbi_fops.open = av7110_vbi_reset,
|
||||||
.vbi_fops.release = av7110_vbi_reset,
|
.vbi_fops.release = av7110_vbi_reset,
|
||||||
.vbi_fops.write = av7110_vbi_write,
|
.vbi_fops.write = av7110_vbi_write,
|
||||||
@@ -918,9 +920,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
|
|||||||
.num_stds = ARRAY_SIZE(standard),
|
.num_stds = ARRAY_SIZE(standard),
|
||||||
.std_callback = &std_callback,
|
.std_callback = &std_callback,
|
||||||
|
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = av7110_ioctl,
|
|
||||||
|
|
||||||
.vbi_fops.open = av7110_vbi_reset,
|
.vbi_fops.open = av7110_vbi_reset,
|
||||||
.vbi_fops.release = av7110_vbi_reset,
|
.vbi_fops.release = av7110_vbi_reset,
|
||||||
.vbi_fops.write = av7110_vbi_write,
|
.vbi_fops.write = av7110_vbi_write,
|
||||||
|
@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KNC1_INPUTS 2
|
||||||
|
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
|
||||||
|
{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
|
||||||
|
{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
||||||
|
{
|
||||||
|
dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
|
||||||
|
if (i->index < 0 || i->index >= KNC1_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
|
||||||
|
|
||||||
|
*i = budget_av->cur_input;
|
||||||
|
|
||||||
|
dprintk(1, "VIDIOC_G_INPUT %d.\n", *i);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct budget_av *budget_av = (struct budget_av *)dev->ext_priv;
|
||||||
|
|
||||||
|
dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
|
||||||
|
return saa7113_setinput(budget_av, input);
|
||||||
|
}
|
||||||
|
|
||||||
static struct saa7146_ext_vv vv_data;
|
static struct saa7146_ext_vv vv_data;
|
||||||
|
|
||||||
static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
|
static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
|
||||||
@@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
|
|||||||
ERR(("cannot init vv subsystem.\n"));
|
ERR(("cannot init vv subsystem.\n"));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
|
||||||
|
vv_data.ops.vidioc_g_input = vidioc_g_input;
|
||||||
|
vv_data.ops.vidioc_s_input = vidioc_s_input;
|
||||||
|
|
||||||
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
|
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
|
||||||
/* fixme: proper cleanup here */
|
/* fixme: proper cleanup here */
|
||||||
@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KNC1_INPUTS 2
|
|
||||||
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
|
|
||||||
{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
|
|
||||||
{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct saa7146_extension_ioctls ioctls[] = {
|
|
||||||
{VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE},
|
|
||||||
{VIDIOC_G_INPUT, SAA7146_EXCLUSIVE},
|
|
||||||
{VIDIOC_S_INPUT, SAA7146_EXCLUSIVE},
|
|
||||||
{0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
|
||||||
{
|
|
||||||
struct saa7146_dev *dev = fh->dev;
|
|
||||||
struct budget_av *budget_av = (struct budget_av *) dev->ext_priv;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case VIDIOC_ENUMINPUT:{
|
|
||||||
struct v4l2_input *i = arg;
|
|
||||||
|
|
||||||
dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
|
|
||||||
if (i->index < 0 || i->index >= KNC1_INPUTS) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_INPUT:{
|
|
||||||
int *input = (int *) arg;
|
|
||||||
|
|
||||||
*input = budget_av->cur_input;
|
|
||||||
|
|
||||||
dprintk(1, "VIDIOC_G_INPUT %d.\n", *input);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_INPUT:{
|
|
||||||
int input = *(int *) arg;
|
|
||||||
dprintk(1, "VIDIOC_S_INPUT %d.\n", input);
|
|
||||||
return saa7113_setinput(budget_av, input);
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct saa7146_standard standard[] = {
|
static struct saa7146_standard standard[] = {
|
||||||
{.name = "PAL",.id = V4L2_STD_PAL,
|
{.name = "PAL",.id = V4L2_STD_PAL,
|
||||||
.v_offset = 0x17,.v_field = 288,
|
.v_offset = 0x17,.v_field = 288,
|
||||||
@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = {
|
|||||||
.flags = 0,
|
.flags = 0,
|
||||||
.stds = &standard[0],
|
.stds = &standard[0],
|
||||||
.num_stds = ARRAY_SIZE(standard),
|
.num_stds = ARRAY_SIZE(standard),
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = av_ioctl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension budget_extension;
|
static struct saa7146_extension budget_extension;
|
||||||
|
@@ -56,17 +56,6 @@ struct hexium_data
|
|||||||
u8 byte;
|
u8 byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension_ioctls ioctls[] = {
|
|
||||||
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_QUERYCTRL, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_STD, SAA7146_AFTER },
|
|
||||||
{ VIDIOC_G_CTRL, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_S_CTRL, SAA7146_BEFORE },
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HEXIUM_CONTROLS 1
|
#define HEXIUM_CONTROLS 1
|
||||||
static struct v4l2_queryctrl hexium_controls[] = {
|
static struct v4l2_queryctrl hexium_controls[] = {
|
||||||
{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
|
{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
|
||||||
@@ -231,6 +220,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
||||||
|
{
|
||||||
|
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
|
||||||
|
|
||||||
|
if (i->index < 0 || i->index >= HEXIUM_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
|
||||||
|
|
||||||
|
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
|
||||||
|
*input = hexium->cur_input;
|
||||||
|
|
||||||
|
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
|
||||||
|
|
||||||
|
if (input < 0 || input >= HEXIUM_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
hexium->cur_input = input;
|
||||||
|
hexium_set_input(hexium, input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the saa7146 provides some controls (brightness, contrast, saturation)
|
||||||
|
which gets registered *after* this function. because of this we have
|
||||||
|
to return with a value != 0 even if the function succeded.. */
|
||||||
|
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (hexium_controls[i].id == qc->id) {
|
||||||
|
*qc = hexium_controls[i];
|
||||||
|
DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (hexium_controls[i].id == vc->id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
|
||||||
|
|
||||||
|
if (vc->id == V4L2_CID_PRIVATE_BASE) {
|
||||||
|
vc->value = hexium->cur_bw;
|
||||||
|
DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (hexium_controls[i].id == vc->id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
|
||||||
|
|
||||||
|
if (vc->id == V4L2_CID_PRIVATE_BASE)
|
||||||
|
hexium->cur_bw = vc->value;
|
||||||
|
|
||||||
|
DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
|
||||||
|
|
||||||
|
if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
|
||||||
|
hexium_set_standard(hexium, hexium_pal);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
|
||||||
|
hexium_set_standard(hexium, hexium_ntsc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
|
||||||
|
hexium_set_standard(hexium, hexium_secam);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
|
||||||
|
hexium_set_standard(hexium, hexium_pal_bw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
|
||||||
|
hexium_set_standard(hexium, hexium_ntsc_bw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
|
||||||
|
/* fixme: is there no bw secam mode? */
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct saa7146_ext_vv vv_data;
|
static struct saa7146_ext_vv vv_data;
|
||||||
|
|
||||||
/* this function only gets called when the probing was successful */
|
/* this function only gets called when the probing was successful */
|
||||||
@@ -279,6 +394,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
|
|||||||
hexium->cur_input = 0;
|
hexium->cur_input = 0;
|
||||||
|
|
||||||
saa7146_vv_init(dev, &vv_data);
|
saa7146_vv_init(dev, &vv_data);
|
||||||
|
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
|
||||||
|
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
|
||||||
|
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
|
||||||
|
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
|
||||||
|
vv_data.ops.vidioc_g_input = vidioc_g_input;
|
||||||
|
vv_data.ops.vidioc_s_input = vidioc_s_input;
|
||||||
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
|
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
|
||||||
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
|
printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -306,153 +427,6 @@ static int hexium_detach(struct saa7146_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
|
||||||
{
|
|
||||||
struct saa7146_dev *dev = fh->dev;
|
|
||||||
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
|
||||||
/*
|
|
||||||
struct saa7146_vv *vv = dev->vv_data;
|
|
||||||
*/
|
|
||||||
switch (cmd) {
|
|
||||||
case VIDIOC_ENUMINPUT:
|
|
||||||
{
|
|
||||||
struct v4l2_input *i = arg;
|
|
||||||
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
|
|
||||||
|
|
||||||
if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
|
|
||||||
|
|
||||||
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_INPUT:
|
|
||||||
{
|
|
||||||
int *input = (int *) arg;
|
|
||||||
*input = hexium->cur_input;
|
|
||||||
|
|
||||||
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_INPUT:
|
|
||||||
{
|
|
||||||
int input = *(int *) arg;
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
|
|
||||||
|
|
||||||
if (input < 0 || input >= HEXIUM_INPUTS) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hexium->cur_input = input;
|
|
||||||
hexium_set_input(hexium, input);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* the saa7146 provides some controls (brightness, contrast, saturation)
|
|
||||||
which gets registered *after* this function. because of this we have
|
|
||||||
to return with a value != 0 even if the function succeded.. */
|
|
||||||
case VIDIOC_QUERYCTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_queryctrl *qc = arg;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (hexium_controls[i].id == qc->id) {
|
|
||||||
*qc = hexium_controls[i];
|
|
||||||
DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_CTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_control *vc = arg;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (hexium_controls[i].id == vc->id) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 0) {
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (vc->id) {
|
|
||||||
case V4L2_CID_PRIVATE_BASE:{
|
|
||||||
vc->value = hexium->cur_bw;
|
|
||||||
DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VIDIOC_S_CTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_control *vc = arg;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (hexium_controls[i].id == vc->id) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 0) {
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (vc->id) {
|
|
||||||
case V4L2_CID_PRIVATE_BASE:{
|
|
||||||
hexium->cur_bw = vc->value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));
|
|
||||||
|
|
||||||
if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
|
|
||||||
hexium_set_standard(hexium, hexium_pal);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
|
|
||||||
hexium_set_standard(hexium, hexium_ntsc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
|
|
||||||
hexium_set_standard(hexium, hexium_secam);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
|
|
||||||
hexium_set_standard(hexium, hexium_pal_bw);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
|
|
||||||
hexium_set_standard(hexium, hexium_ntsc_bw);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
|
|
||||||
/* fixme: is there no bw secam mode? */
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
|
|
||||||
*/
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
|
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
|
||||||
{
|
{
|
||||||
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = {
|
|||||||
.stds = &hexium_standards[0],
|
.stds = &hexium_standards[0],
|
||||||
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
|
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
|
||||||
.std_callback = &std_callback,
|
.std_callback = &std_callback,
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = hexium_ioctl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension hexium_extension = {
|
static struct saa7146_extension hexium_extension = {
|
||||||
|
@@ -57,14 +57,6 @@ struct hexium_data
|
|||||||
u8 byte;
|
u8 byte;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension_ioctls ioctls[] = {
|
|
||||||
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_STD, SAA7146_AFTER },
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hexium
|
struct hexium
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
@@ -329,6 +321,44 @@ static int hexium_set_input(struct hexium *hexium, int input)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
||||||
|
{
|
||||||
|
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
|
||||||
|
|
||||||
|
if (i->index < 0 || i->index >= HEXIUM_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
|
||||||
|
|
||||||
|
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
|
||||||
|
*input = hexium->cur_input;
|
||||||
|
|
||||||
|
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
||||||
|
|
||||||
|
if (input < 0 || input >= HEXIUM_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
hexium->cur_input = input;
|
||||||
|
hexium_set_input(hexium, input);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct saa7146_ext_vv vv_data;
|
static struct saa7146_ext_vv vv_data;
|
||||||
|
|
||||||
/* this function only gets called when the probing was successful */
|
/* this function only gets called when the probing was successful */
|
||||||
@@ -339,6 +369,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
|
|||||||
DEB_EE((".\n"));
|
DEB_EE((".\n"));
|
||||||
|
|
||||||
saa7146_vv_init(dev, &vv_data);
|
saa7146_vv_init(dev, &vv_data);
|
||||||
|
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
|
||||||
|
vv_data.ops.vidioc_g_input = vidioc_g_input;
|
||||||
|
vv_data.ops.vidioc_s_input = vidioc_s_input;
|
||||||
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
|
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
|
||||||
printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
|
printk("hexium_orion: cannot register capture v4l2 device. skipping.\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -370,58 +403,6 @@ static int hexium_detach(struct saa7146_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
|
||||||
{
|
|
||||||
struct saa7146_dev *dev = fh->dev;
|
|
||||||
struct hexium *hexium = (struct hexium *) dev->ext_priv;
|
|
||||||
/*
|
|
||||||
struct saa7146_vv *vv = dev->vv_data;
|
|
||||||
*/
|
|
||||||
switch (cmd) {
|
|
||||||
case VIDIOC_ENUMINPUT:
|
|
||||||
{
|
|
||||||
struct v4l2_input *i = arg;
|
|
||||||
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
|
|
||||||
|
|
||||||
if (i->index < 0 || i->index >= HEXIUM_INPUTS) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
|
|
||||||
|
|
||||||
DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_INPUT:
|
|
||||||
{
|
|
||||||
int *input = (int *) arg;
|
|
||||||
*input = hexium->cur_input;
|
|
||||||
|
|
||||||
DEB_D(("VIDIOC_G_INPUT: %d\n", *input));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_INPUT:
|
|
||||||
{
|
|
||||||
int input = *(int *) arg;
|
|
||||||
|
|
||||||
if (input < 0 || input >= HEXIUM_INPUTS) {
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hexium->cur_input = input;
|
|
||||||
hexium_set_input(hexium, input);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
DEB_D(("hexium_ioctl() does not handle this ioctl.\n"));
|
|
||||||
*/
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
|
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@@ -479,8 +460,6 @@ static struct saa7146_ext_vv vv_data = {
|
|||||||
.stds = &hexium_standards[0],
|
.stds = &hexium_standards[0],
|
||||||
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
|
.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
|
||||||
.std_callback = &std_callback,
|
.std_callback = &std_callback,
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = hexium_ioctl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension extension = {
|
static struct saa7146_extension extension = {
|
||||||
|
@@ -110,26 +110,6 @@ static struct v4l2_queryctrl mxb_controls[] = {
|
|||||||
{ V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
|
{ V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension_ioctls ioctls[] = {
|
|
||||||
{ VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_INPUT, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_QUERYCTRL, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_G_CTRL, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_S_CTRL, SAA7146_BEFORE },
|
|
||||||
{ VIDIOC_G_TUNER, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_TUNER, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE },
|
|
||||||
{ VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE },
|
|
||||||
{ MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */
|
|
||||||
{ MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */
|
|
||||||
{ 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct mxb
|
struct mxb
|
||||||
{
|
{
|
||||||
struct video_device *video_dev;
|
struct video_device *video_dev;
|
||||||
@@ -424,6 +404,351 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (mxb_controls[i].id == qc->id) {
|
||||||
|
*qc = mxb_controls[i];
|
||||||
|
DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (mxb_controls[i].id == vc->id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
|
||||||
|
|
||||||
|
if (vc->id == V4L2_CID_AUDIO_MUTE) {
|
||||||
|
vc->value = mxb->cur_mute;
|
||||||
|
DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
||||||
|
if (mxb_controls[i].id == vc->id)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
|
||||||
|
|
||||||
|
if (vc->id == V4L2_CID_AUDIO_MUTE) {
|
||||||
|
mxb->cur_mute = vc->value;
|
||||||
|
if (!vc->value) {
|
||||||
|
/* switch the audio-source */
|
||||||
|
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
|
||||||
|
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
|
||||||
|
} else {
|
||||||
|
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[6][0]);
|
||||||
|
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[6][1]);
|
||||||
|
}
|
||||||
|
DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
|
||||||
|
{
|
||||||
|
DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
|
||||||
|
if (i->index < 0 || i->index >= MXB_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
*i = mxb->cur_input;
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_G_INPUT %d.\n", *i));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
struct tea6415c_multiplex vm;
|
||||||
|
struct v4l2_routing route;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
|
||||||
|
|
||||||
|
if (input < 0 || input >= MXB_INPUTS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mxb->cur_input = input;
|
||||||
|
|
||||||
|
saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
|
||||||
|
input_port_selection[input].hps_sync);
|
||||||
|
|
||||||
|
/* prepare switching of tea6415c and saa7111a;
|
||||||
|
have a look at the 'background'-file for further informations */
|
||||||
|
switch (input) {
|
||||||
|
case TUNER:
|
||||||
|
i = SAA7115_COMPOSITE0;
|
||||||
|
vm.in = 3;
|
||||||
|
vm.out = 17;
|
||||||
|
|
||||||
|
if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
|
||||||
|
printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
/* connect tuner-output always to multicable */
|
||||||
|
vm.in = 3;
|
||||||
|
vm.out = 13;
|
||||||
|
break;
|
||||||
|
case AUX3_YC:
|
||||||
|
/* nothing to be done here. aux3_yc is
|
||||||
|
directly connected to the saa711a */
|
||||||
|
i = SAA7115_SVIDEO1;
|
||||||
|
break;
|
||||||
|
case AUX3:
|
||||||
|
/* nothing to be done here. aux3 is
|
||||||
|
directly connected to the saa711a */
|
||||||
|
i = SAA7115_COMPOSITE1;
|
||||||
|
break;
|
||||||
|
case AUX1:
|
||||||
|
i = SAA7115_COMPOSITE0;
|
||||||
|
vm.in = 1;
|
||||||
|
vm.out = 17;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch video in tea6415c only if necessary */
|
||||||
|
switch (input) {
|
||||||
|
case TUNER:
|
||||||
|
case AUX1:
|
||||||
|
if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
|
||||||
|
printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch video in saa7111a */
|
||||||
|
route.input = i;
|
||||||
|
route.output = 0;
|
||||||
|
if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
|
||||||
|
printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
|
||||||
|
|
||||||
|
/* switch the audio-source only if necessary */
|
||||||
|
if (0 == mxb->cur_mute) {
|
||||||
|
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[video_audio_connect[input]][0]);
|
||||||
|
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
||||||
|
&TEA6420_line[video_audio_connect[input]][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
if (t->index) {
|
||||||
|
DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
|
||||||
|
|
||||||
|
memset(t, 0, sizeof(*t));
|
||||||
|
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t);
|
||||||
|
|
||||||
|
strlcpy(t->name, "TV Tuner", sizeof(t->name));
|
||||||
|
t->type = V4L2_TUNER_ANALOG_TV;
|
||||||
|
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
|
||||||
|
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
||||||
|
t->audmode = mxb->cur_mode;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
if (t->index) {
|
||||||
|
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mxb->cur_mode = t->audmode;
|
||||||
|
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
if (mxb->cur_input) {
|
||||||
|
DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
|
||||||
|
mxb->cur_input));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*f = mxb->cur_freq;
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
struct saa7146_vv *vv = dev->vv_data;
|
||||||
|
|
||||||
|
if (f->tuner)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (V4L2_TUNER_ANALOG_TV != f->type)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (mxb->cur_input) {
|
||||||
|
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mxb->cur_freq = *f;
|
||||||
|
DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
|
||||||
|
|
||||||
|
/* tune in desired frequency */
|
||||||
|
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
|
||||||
|
|
||||||
|
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
|
||||||
|
spin_lock(&dev->slock);
|
||||||
|
vv->vbi_fieldcount = 0;
|
||||||
|
spin_unlock(&dev->slock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
if (a->index < 0 || a->index > MXB_INPUTS) {
|
||||||
|
DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
|
||||||
|
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
|
||||||
|
{
|
||||||
|
DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_G_REGISTER, reg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_S_REGISTER, reg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
|
||||||
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case MXB_S_AUDIO_CD:
|
||||||
|
{
|
||||||
|
int i = *(int *)arg;
|
||||||
|
|
||||||
|
if (i < 0 || i >= MXB_AUDIOS) {
|
||||||
|
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
|
||||||
|
|
||||||
|
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]);
|
||||||
|
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case MXB_S_AUDIO_LINE:
|
||||||
|
{
|
||||||
|
int i = *(int *)arg;
|
||||||
|
|
||||||
|
if (i < 0 || i >= MXB_AUDIOS) {
|
||||||
|
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
|
||||||
|
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]);
|
||||||
|
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
DEB2(printk("does not handle this ioctl.\n"));
|
||||||
|
*/
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct saa7146_ext_vv vv_data;
|
static struct saa7146_ext_vv vv_data;
|
||||||
|
|
||||||
/* this function only gets called when the probing was successful */
|
/* this function only gets called when the probing was successful */
|
||||||
@@ -437,6 +762,23 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
|
|||||||
already did this in "mxb_vl42_probe" */
|
already did this in "mxb_vl42_probe" */
|
||||||
|
|
||||||
saa7146_vv_init(dev, &vv_data);
|
saa7146_vv_init(dev, &vv_data);
|
||||||
|
vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
|
||||||
|
vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
|
||||||
|
vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
|
||||||
|
vv_data.ops.vidioc_enum_input = vidioc_enum_input;
|
||||||
|
vv_data.ops.vidioc_g_input = vidioc_g_input;
|
||||||
|
vv_data.ops.vidioc_s_input = vidioc_s_input;
|
||||||
|
vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
|
||||||
|
vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
|
||||||
|
vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
|
||||||
|
vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
|
||||||
|
vv_data.ops.vidioc_g_audio = vidioc_g_audio;
|
||||||
|
vv_data.ops.vidioc_s_audio = vidioc_s_audio;
|
||||||
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||||
|
vv_data.ops.vidioc_g_register = vidioc_g_register;
|
||||||
|
vv_data.ops.vidioc_s_register = vidioc_s_register;
|
||||||
|
#endif
|
||||||
|
vv_data.ops.vidioc_default = vidioc_default;
|
||||||
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
|
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
|
||||||
ERR(("cannot register capture v4l2 device. skipping.\n"));
|
ERR(("cannot register capture v4l2 device. skipping.\n"));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -489,325 +831,6 @@ static int mxb_detach(struct saa7146_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
|
|
||||||
{
|
|
||||||
struct saa7146_dev *dev = fh->dev;
|
|
||||||
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
|
||||||
struct saa7146_vv *vv = dev->vv_data;
|
|
||||||
|
|
||||||
switch(cmd) {
|
|
||||||
case VIDIOC_ENUMINPUT:
|
|
||||||
{
|
|
||||||
struct v4l2_input *i = arg;
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index));
|
|
||||||
if (i->index < 0 || i->index >= MXB_INPUTS)
|
|
||||||
return -EINVAL;
|
|
||||||
memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* the saa7146 provides some controls (brightness, contrast, saturation)
|
|
||||||
which gets registered *after* this function. because of this we have
|
|
||||||
to return with a value != 0 even if the function succeded.. */
|
|
||||||
case VIDIOC_QUERYCTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_queryctrl *qc = arg;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (mxb_controls[i].id == qc->id) {
|
|
||||||
*qc = mxb_controls[i];
|
|
||||||
DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -EAGAIN;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_CTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_control *vc = arg;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (mxb_controls[i].id == vc->id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 0)
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
if (vc->id == V4L2_CID_AUDIO_MUTE) {
|
|
||||||
vc->value = mxb->cur_mute;
|
|
||||||
DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VIDIOC_S_CTRL:
|
|
||||||
{
|
|
||||||
struct v4l2_control *vc = arg;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
for (i = MAXCONTROLS - 1; i >= 0; i--) {
|
|
||||||
if (mxb_controls[i].id == vc->id)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < 0)
|
|
||||||
return -EAGAIN;
|
|
||||||
|
|
||||||
if (vc->id == V4L2_CID_AUDIO_MUTE) {
|
|
||||||
mxb->cur_mute = vc->value;
|
|
||||||
if (!vc->value) {
|
|
||||||
/* switch the audio-source */
|
|
||||||
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
|
|
||||||
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
|
|
||||||
} else {
|
|
||||||
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[6][0]);
|
|
||||||
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[6][1]);
|
|
||||||
}
|
|
||||||
DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_INPUT:
|
|
||||||
{
|
|
||||||
int *input = (int *)arg;
|
|
||||||
*input = mxb->cur_input;
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_G_INPUT %d.\n", *input));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_INPUT:
|
|
||||||
{
|
|
||||||
int input = *(int *)arg;
|
|
||||||
struct tea6415c_multiplex vm;
|
|
||||||
struct v4l2_routing route;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_S_INPUT %d.\n", input));
|
|
||||||
|
|
||||||
if (input < 0 || input >= MXB_INPUTS)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mxb->cur_input = input;
|
|
||||||
|
|
||||||
saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source,
|
|
||||||
input_port_selection[input].hps_sync);
|
|
||||||
|
|
||||||
/* prepare switching of tea6415c and saa7111a;
|
|
||||||
have a look at the 'background'-file for further informations */
|
|
||||||
switch (input) {
|
|
||||||
case TUNER:
|
|
||||||
i = SAA7115_COMPOSITE0;
|
|
||||||
vm.in = 3;
|
|
||||||
vm.out = 17;
|
|
||||||
|
|
||||||
if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
|
|
||||||
printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
/* connect tuner-output always to multicable */
|
|
||||||
vm.in = 3;
|
|
||||||
vm.out = 13;
|
|
||||||
break;
|
|
||||||
case AUX3_YC:
|
|
||||||
/* nothing to be done here. aux3_yc is
|
|
||||||
directly connected to the saa711a */
|
|
||||||
i = SAA7115_SVIDEO1;
|
|
||||||
break;
|
|
||||||
case AUX3:
|
|
||||||
/* nothing to be done here. aux3 is
|
|
||||||
directly connected to the saa711a */
|
|
||||||
i = SAA7115_COMPOSITE1;
|
|
||||||
break;
|
|
||||||
case AUX1:
|
|
||||||
i = SAA7115_COMPOSITE0;
|
|
||||||
vm.in = 1;
|
|
||||||
vm.out = 17;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* switch video in tea6415c only if necessary */
|
|
||||||
switch (input) {
|
|
||||||
case TUNER:
|
|
||||||
case AUX1:
|
|
||||||
if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
|
|
||||||
printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* switch video in saa7111a */
|
|
||||||
route.input = i;
|
|
||||||
route.output = 0;
|
|
||||||
if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
|
|
||||||
printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n");
|
|
||||||
|
|
||||||
/* switch the audio-source only if necessary */
|
|
||||||
if( 0 == mxb->cur_mute ) {
|
|
||||||
mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[video_audio_connect[input]][0]);
|
|
||||||
mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
|
|
||||||
&TEA6420_line[video_audio_connect[input]][1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_TUNER:
|
|
||||||
{
|
|
||||||
struct v4l2_tuner *t = arg;
|
|
||||||
|
|
||||||
if (t->index) {
|
|
||||||
DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
|
|
||||||
|
|
||||||
memset(t, 0, sizeof(*t));
|
|
||||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
|
||||||
|
|
||||||
strlcpy(t->name, "TV Tuner", sizeof(t->name));
|
|
||||||
t->type = V4L2_TUNER_ANALOG_TV;
|
|
||||||
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \
|
|
||||||
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
|
|
||||||
t->audmode = mxb->cur_mode;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_TUNER:
|
|
||||||
{
|
|
||||||
struct v4l2_tuner *t = arg;
|
|
||||||
|
|
||||||
if (t->index) {
|
|
||||||
DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mxb->cur_mode = t->audmode;
|
|
||||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_FREQUENCY:
|
|
||||||
{
|
|
||||||
struct v4l2_frequency *f = arg;
|
|
||||||
|
|
||||||
if (mxb->cur_input) {
|
|
||||||
DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
|
|
||||||
mxb->cur_input));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*f = mxb->cur_freq;
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_FREQUENCY:
|
|
||||||
{
|
|
||||||
struct v4l2_frequency *f = arg;
|
|
||||||
|
|
||||||
if (f->tuner)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (V4L2_TUNER_ANALOG_TV != f->type)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (mxb->cur_input) {
|
|
||||||
DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mxb->cur_freq = *f;
|
|
||||||
DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
|
|
||||||
|
|
||||||
/* tune in desired frequency */
|
|
||||||
mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
|
|
||||||
|
|
||||||
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
|
|
||||||
spin_lock(&dev->slock);
|
|
||||||
vv->vbi_fieldcount = 0;
|
|
||||||
spin_unlock(&dev->slock);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case MXB_S_AUDIO_CD:
|
|
||||||
{
|
|
||||||
int i = *(int*)arg;
|
|
||||||
|
|
||||||
if (i < 0 || i >= MXB_AUDIOS) {
|
|
||||||
DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i));
|
|
||||||
|
|
||||||
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]);
|
|
||||||
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case MXB_S_AUDIO_LINE:
|
|
||||||
{
|
|
||||||
int i = *(int*)arg;
|
|
||||||
|
|
||||||
if (i < 0 || i >= MXB_AUDIOS) {
|
|
||||||
DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i));
|
|
||||||
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]);
|
|
||||||
mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_G_AUDIO:
|
|
||||||
{
|
|
||||||
struct v4l2_audio *a = arg;
|
|
||||||
|
|
||||||
if (a->index < 0 || a->index > MXB_INPUTS) {
|
|
||||||
DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index));
|
|
||||||
memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
case VIDIOC_S_AUDIO:
|
|
||||||
{
|
|
||||||
struct v4l2_audio *a = arg;
|
|
||||||
|
|
||||||
DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
||||||
case VIDIOC_DBG_S_REGISTER:
|
|
||||||
case VIDIOC_DBG_G_REGISTER:
|
|
||||||
i2c_clients_command(&mxb->i2c_adapter, cmd, arg);
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
/*
|
|
||||||
DEB2(printk("does not handle this ioctl.\n"));
|
|
||||||
*/
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
|
static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard)
|
||||||
{
|
{
|
||||||
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
struct mxb *mxb = (struct mxb *)dev->ext_priv;
|
||||||
@@ -885,8 +908,6 @@ static struct saa7146_ext_vv vv_data = {
|
|||||||
.stds = &standard[0],
|
.stds = &standard[0],
|
||||||
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
|
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
|
||||||
.std_callback = &std_callback,
|
.std_callback = &std_callback,
|
||||||
.ioctls = &ioctls[0],
|
|
||||||
.ioctl = mxb_ioctl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct saa7146_extension extension = {
|
static struct saa7146_extension extension = {
|
||||||
|
@@ -150,16 +150,6 @@ struct saa7146_vv
|
|||||||
unsigned int resources; /* resource management for device */
|
unsigned int resources; /* resource management for device */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SAA7146_EXCLUSIVE 0x1
|
|
||||||
#define SAA7146_BEFORE 0x2
|
|
||||||
#define SAA7146_AFTER 0x4
|
|
||||||
|
|
||||||
struct saa7146_extension_ioctls
|
|
||||||
{
|
|
||||||
unsigned int cmd;
|
|
||||||
int flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
|
#define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */
|
||||||
|
|
||||||
@@ -176,8 +166,10 @@ struct saa7146_ext_vv
|
|||||||
int num_stds;
|
int num_stds;
|
||||||
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
|
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
|
||||||
|
|
||||||
struct saa7146_extension_ioctls *ioctls;
|
/* the extension can override this */
|
||||||
long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg);
|
struct v4l2_ioctl_ops ops;
|
||||||
|
/* pointer to the saa7146 core ops */
|
||||||
|
const struct v4l2_ioctl_ops *core_ops;
|
||||||
|
|
||||||
struct v4l2_file_operations vbi_fops;
|
struct v4l2_file_operations vbi_fops;
|
||||||
};
|
};
|
||||||
@@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy
|
|||||||
void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
|
void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
|
||||||
|
|
||||||
/* from saa7146_video.c */
|
/* from saa7146_video.c */
|
||||||
|
extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
|
||||||
extern struct saa7146_use_ops saa7146_video_uops;
|
extern struct saa7146_use_ops saa7146_video_uops;
|
||||||
int saa7146_start_preview(struct saa7146_fh *fh);
|
int saa7146_start_preview(struct saa7146_fh *fh);
|
||||||
int saa7146_stop_preview(struct saa7146_fh *fh);
|
int saa7146_stop_preview(struct saa7146_fh *fh);
|
||||||
|
Reference in New Issue
Block a user