Commit b960074f authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent c9b8b04b
Loading
Loading
Loading
Loading
+14 −22
Original line number Diff line number Diff line
@@ -308,14 +308,6 @@ static int fops_release(struct file *file)
	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)
{
	struct saa7146_fh *fh = file->private_data;
@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops =
	.write		= fops_write,
	.poll		= fops_poll,
	.mmap		= fops_mmap,
	.ioctl		= fops_ioctl,
	.ioctl		= video_ioctl2,
};

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)
{
	struct saa7146_vv *vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
	if( NULL == vv ) {

	if (vv == NULL) {
		ERR(("out of memory. aborting.\n"));
		return -1;
	}
	ext_vv->ops = saa7146_video_ioctl_ops;
	ext_vv->core_ops = &saa7146_video_ioctl_ops;

	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 video_device *vfd;
	int err;

	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)
		return -ENOMEM;

	memcpy(vfd, &device_template, sizeof(struct video_device));
	strlcpy(vfd->name, name, sizeof(vfd->name));
	vfd->fops = &video_fops;
	vfd->ioctl_ops = dev->ext_vv_data ? &dev->ext_vv_data->ops :
						&saa7146_video_ioctl_ops;
	vfd->release = video_device_release;
	strlcpy(vfd->name, name, sizeof(vfd->name));
	video_set_drvdata(vfd, dev);

	// fixme: -1 should be an insmod parameter *for the extension* (like "video_nr");
	if (video_register_device(vfd, type, -1) < 0) {
	err = video_register_device(vfd, type, -1);
	if (err < 0) {
		ERR(("cannot register v4l2 device. skipping.\n"));
		video_device_release(vfd);
		return -1;
		return err;
	}

	if( VFL_TYPE_GRABBER == type ) {
+604 −654

File changed.

Preview size limit exceeded, changes collapsed.

+239 −240
Original line number Diff line number Diff line
@@ -316,16 +316,10 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
	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;
	dprintk(4, "saa7146_dev: %p\n", dev);

	switch (cmd) {
	case VIDIOC_G_TUNER:
	{
		struct v4l2_tuner *t = arg;
	u16 stereo_det;
	s8 stereo;

@@ -346,7 +340,7 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	t->signal = 0xffff;
	t->afc = 0;

		// FIXME: standard / stereo detection is still broken
	/* FIXME: standard / stereo detection is still broken */
	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);
@@ -356,20 +350,20 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
		/* stereo */
		t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
		t->audmode = V4L2_TUNER_MODE_STEREO;
		}
		else if (stereo < -0x10) {
	} else if (stereo < -0x10) {
		/* bilingual */
		t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
		t->audmode = V4L2_TUNER_MODE_LANG1;
		}
		else /* mono */
	} else /* mono */
		t->rxsubchans = V4L2_TUNER_SUB_MONO;

	return 0;
}
	case VIDIOC_S_TUNER:

static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
{
		struct v4l2_tuner *t = arg;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
	u16 fm_matrix, src;
	dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);

@@ -379,27 +373,27 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	switch (t->audmode) {
	case V4L2_TUNER_MODE_STEREO:
		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n");
			fm_matrix = 0x3001; // stereo
		fm_matrix = 0x3001; /* stereo */
		src = 0x0020;
		break;
	case V4L2_TUNER_MODE_LANG1_LANG2:
		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n");
			fm_matrix = 0x3000; // bilingual
		fm_matrix = 0x3000; /* bilingual */
		src = 0x0020;
		break;
	case V4L2_TUNER_MODE_LANG1:
		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n");
			fm_matrix = 0x3000; // mono
		fm_matrix = 0x3000; /* mono */
		src = 0x0000;
		break;
	case V4L2_TUNER_MODE_LANG2:
		dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n");
			fm_matrix = 0x3000; // mono
		fm_matrix = 0x3000; /* mono */
		src = 0x0010;
		break;
	default: /* case V4L2_TUNER_MODE_MONO: */
		dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n");
			fm_matrix = 0x3000; // mono
		fm_matrix = 0x3000; /* mono */
		src = 0x0030;
		break;
	}
@@ -409,9 +403,11 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	msp_writereg(av7110, MSP_WR_DSP, 0x000a, src);
	return 0;
}
	case VIDIOC_G_FREQUENCY:

static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
		struct v4l2_frequency *f = arg;
	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);

@@ -423,9 +419,11 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	f->frequency =	av7110->current_freq;
	return 0;
}
	case VIDIOC_S_FREQUENCY:

static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
		struct v4l2_frequency *f = arg;
	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);

@@ -435,26 +433,27 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	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, 0x0000, 0xffe0); /* fast mute */
	msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0);

	/* tune in desired frequency */
		if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) {
	if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820)
		ves1820_set_tv_freq(dev, f->frequency);
		} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
	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, 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
	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:

static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
		struct v4l2_input *i = arg;
	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);

@@ -470,16 +469,21 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)

	return 0;
}
	case VIDIOC_G_INPUT:

static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
		int *input = (int *)arg;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;

	*input = av7110->current_input;
	dprintk(2, "VIDIOC_G_INPUT: %d\n", *input);
	return 0;
}
	case VIDIOC_S_INPUT:

static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
		int input = *(int *)arg;
	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);

@@ -492,65 +496,74 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
	av7110->current_input = input;
	return av7110_dvb_c_switch(fh);
}
	case VIDIOC_G_AUDIO:
	{
		struct v4l2_audio *a = arg;

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));
		break;
	return 0;
}
	case VIDIOC_S_AUDIO:

static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
		struct v4l2_audio *a = arg;
	dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
		break;
	return 0;
}
	case VIDIOC_G_SLICED_VBI_CAP:

static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
					struct v4l2_sliced_vbi_cap *cap)
{
		struct v4l2_sliced_vbi_cap *cap = arg;
	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);
	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;
	}
		break;
	return 0;
}
	case VIDIOC_G_FMT:

static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
					struct v4l2_format *f)
{
		struct v4l2_format *f = arg;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;

	dprintk(2, "VIDIOC_G_FMT:\n");
		if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
		    FW_VERSION(av7110->arm_app) < 0x2623)
			return -EAGAIN; /* handled by core driver */
	if (FW_VERSION(av7110->arm_app) < 0x2623)
		return -EINVAL;
	memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
	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);
	}
		break;
	return 0;
}
	case VIDIOC_S_FMT:

static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
					struct v4l2_format *f)
{
		struct v4l2_format *f = arg;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;

	dprintk(2, "VIDIOC_S_FMT\n");
		if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ||
		    FW_VERSION(av7110->arm_app) < 0x2623)
			return -EAGAIN; /* handled by core driver */
	if (FW_VERSION(av7110->arm_app) < 0x2623)
		return -EINVAL;
	if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 &&
	    f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) {
			memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
		/* WSS controlled by firmware */
		av7110->wssMode = 0;
		av7110->wssData = 0;
		return av7110_fw_cmd(av7110, COMTYPE_ENCODER,
				     SetWSSConfig, 1, 0);
	} else {
			memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
		memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
		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);
@@ -558,12 +571,6 @@ static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
		av7110->wssMode = 1;
		av7110->wssData = 0;
	}
		break;
	}
	default:
		printk("no such ioctl\n");
		return -ENOIOCTLCMD;
	}
	return 0;
}

@@ -609,22 +616,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size
 * 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[] = {
	0x02, 0xd0,
	0x03, 0x23,
@@ -788,20 +779,34 @@ int av7110_init_analog_module(struct av7110 *av7110)
int av7110_init_v4l(struct av7110 *av7110)
{
	struct saa7146_dev* dev = av7110->dev;
	struct saa7146_ext_vv *vv_data;
	int ret;

	/* special case DVB-C: these cards have an analog tuner
	   plus need some special handling, so we have separate
	   saa7146_ext_vv data for these... */
	if (av7110->analog_tuner_flags)
		ret = saa7146_vv_init(dev, &av7110_vv_data_c);
		vv_data = &av7110_vv_data_c;
	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) {
		ERR(("cannot init capture device. skipping.\n"));
		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)) {
		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),
	.std_callback	= &std_callback,

	.ioctls		= &ioctls[0],
	.ioctl		= av7110_ioctl,

	.vbi_fops.open	= av7110_vbi_reset,
	.vbi_fops.release = av7110_vbi_reset,
	.vbi_fops.write	= av7110_vbi_write,
@@ -918,9 +920,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = {
	.num_stds	= ARRAY_SIZE(standard),
	.std_callback	= &std_callback,

	.ioctls		= &ioctls[0],
	.ioctl		= av7110_ioctl,

	.vbi_fops.open	= av7110_vbi_reset,
	.vbi_fops.release = av7110_vbi_reset,
	.vbi_fops.write	= av7110_vbi_write,
+38 −50
Original line number Diff line number Diff line
@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev)
	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 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"));
			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))) {
			/* fixme: proper cleanup here */
@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
	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[] = {
	{.name = "PAL",.id = V4L2_STD_PAL,
	 .v_offset = 0x17,.v_field = 288,
@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = {
	.flags = 0,
	.stds = &standard[0],
	.num_stds = ARRAY_SIZE(standard),
	.ioctls = &ioctls[0],
	.ioctl = av_ioctl,
};

static struct saa7146_extension budget_extension;
+132 −160
Original line number Diff line number Diff line
@@ -56,17 +56,6 @@ struct hexium_data
	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
static struct v4l2_queryctrl hexium_controls[] = {
	{ V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
@@ -231,132 +220,51 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec)
	return 0;
}

static struct saa7146_ext_vv vv_data;

/* this function only gets called when the probing was successful */
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
	struct hexium *hexium = (struct hexium *) dev->ext_priv;

	DEB_EE((".\n"));

	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
	if (NULL == hexium) {
		printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
		return -ENOMEM;
	}
	dev->ext_priv = hexium;

	/* enable i2c-port pins */
	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));

	hexium->i2c_adapter = (struct i2c_adapter) {
		.class = I2C_CLASS_TV_ANALOG,
		.name = "hexium gemini",
	};
	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
		DEB_S(("cannot register i2c-device. skipping.\n"));
		kfree(hexium);
		return -EFAULT;
	}

	/*  set HWControl GPIO number 2 */
	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);

	saa7146_write(dev, DD1_INIT, 0x07000700);
	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));

	/* the rest */
	hexium->cur_input = 0;
	hexium_init_done(dev);

	hexium_set_standard(hexium, hexium_pal);
	hexium->cur_std = V4L2_STD_PAL;

	hexium_set_input(hexium, 0);
	hexium->cur_input = 0;

	saa7146_vv_init(dev, &vv_data);
	if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) {
		printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
		return -1;
	}

	printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
	hexium_num++;

	return 0;
}

static int hexium_detach(struct saa7146_dev *dev)
{
	struct hexium *hexium = (struct hexium *) dev->ext_priv;

	DEB_EE(("dev:%p\n", dev));

	saa7146_unregister_device(&hexium->video_dev, dev);
	saa7146_vv_release(dev);

	hexium_num--;

	i2c_del_adapter(&hexium->i2c_adapter);
	kfree(hexium);
	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) {
	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:

static int vidioc_g_input(struct file *file, void *fh, unsigned int *input)
{
			int *input = (int *) arg;
	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;
}
	case VIDIOC_S_INPUT:

static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
			int input = *(int *) arg;
	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) {
	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:
static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
{
			struct v4l2_queryctrl *qc = arg;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	int i;

	for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
@@ -366,54 +274,47 @@ static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
			return 0;
		}
	}
			return -EAGAIN;
	return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
}
	case VIDIOC_G_CTRL:

static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
			struct v4l2_control *vc = arg;
	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) {
		if (hexium_controls[i].id == vc->id)
			break;
	}
			}

			if (i < 0) {
				return -EAGAIN;
			}
	if (i < 0)
		return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);

			switch (vc->id) {
			case V4L2_CID_PRIVATE_BASE:{
	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;
}

	case VIDIOC_S_CTRL:
static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
{
			struct v4l2_control *vc = arg;
	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) {
		if (hexium_controls[i].id == vc->id)
			break;
	}
			}

			if (i < 0) {
				return -EAGAIN;
			}
	if (i < 0)
		return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);

			switch (vc->id) {
			case V4L2_CID_PRIVATE_BASE:{
	if (vc->id == V4L2_CID_PRIVATE_BASE)
		hexium->cur_bw = vc->value;
					break;
				}
			}

	DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw));

@@ -437,19 +338,92 @@ static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
		hexium_set_standard(hexium, hexium_ntsc_bw);
		return 0;
	}
			if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
	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;


static struct saa7146_ext_vv vv_data;

/* this function only gets called when the probing was successful */
static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
{
	struct hexium *hexium = (struct hexium *) dev->ext_priv;

	DEB_EE((".\n"));

	hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL);
	if (NULL == hexium) {
		printk("hexium_gemini: not enough kernel memory in hexium_attach().\n");
		return -ENOMEM;
	}
	dev->ext_priv = hexium;

	/* enable i2c-port pins */
	saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));

	hexium->i2c_adapter = (struct i2c_adapter) {
		.class = I2C_CLASS_TV_ANALOG,
		.name = "hexium gemini",
	};
	saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
	if (i2c_add_adapter(&hexium->i2c_adapter) < 0) {
		DEB_S(("cannot register i2c-device. skipping.\n"));
		kfree(hexium);
		return -EFAULT;
	}

	/*  set HWControl GPIO number 2 */
	saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);

	saa7146_write(dev, DD1_INIT, 0x07000700);
	saa7146_write(dev, DD1_STREAM_B, 0x00000000);
	saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));

	/* the rest */
	hexium->cur_input = 0;
	hexium_init_done(dev);

	hexium_set_standard(hexium, hexium_pal);
	hexium->cur_std = V4L2_STD_PAL;

	hexium_set_input(hexium, 0);
	hexium->cur_input = 0;

	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)) {
		printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n");
		return -1;
	}

	printk("hexium_gemini: found 'hexium gemini' frame grabber-%d.\n", hexium_num);
	hexium_num++;

	return 0;
}

static int hexium_detach(struct saa7146_dev *dev)
{
	struct hexium *hexium = (struct hexium *) dev->ext_priv;

	DEB_EE(("dev:%p\n", dev));

	saa7146_unregister_device(&hexium->video_dev, dev);
	saa7146_vv_release(dev);

	hexium_num--;

	i2c_del_adapter(&hexium->i2c_adapter);
	kfree(hexium);
	return 0;
}

@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = {
	.stds = &hexium_standards[0],
	.num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard),
	.std_callback = &std_callback,
	.ioctls = &ioctls[0],
	.ioctl = hexium_ioctl,
};

static struct saa7146_extension hexium_extension = {
Loading