Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

V4L/DVB (10499): saa7146: convert saa7146 and mxb in particular to v4l2_subdev.



Modified mxb to load the i2c modules through v4l2_subdev. So no more probing.
Modified tea6415c and tea6420 to use the standard routing ops to do the
routing, rather than using private commands. Dropped the private commands
from tda9840 (they were never used except during initialization of the
module).

Added saa7146 support for VIDIOC_DBG_G_CHIP_IDENT.

Converted saa5246a and saa5249 to v4l2_subdev.

Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d30e21dd
Loading
Loading
Loading
Loading
+23 −2
Original line number Original line Diff line number Diff line
#include <media/saa7146_vv.h>
#include <media/saa7146_vv.h>
#include <media/v4l2-chip-ident.h>


static int max_memory = 32;
static int max_memory = 32;


@@ -209,6 +210,7 @@ static struct v4l2_queryctrl controls[] = {
		.step		= 1,
		.step		= 1,
		.default_value	= 128,
		.default_value	= 128,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.flags 		= V4L2_CTRL_FLAG_SLIDER,
	},{
	},{
		.id		= V4L2_CID_CONTRAST,
		.id		= V4L2_CID_CONTRAST,
		.name		= "Contrast",
		.name		= "Contrast",
@@ -217,6 +219,7 @@ static struct v4l2_queryctrl controls[] = {
		.step		= 1,
		.step		= 1,
		.default_value	= 64,
		.default_value	= 64,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.flags 		= V4L2_CTRL_FLAG_SLIDER,
	},{
	},{
		.id		= V4L2_CID_SATURATION,
		.id		= V4L2_CID_SATURATION,
		.name		= "Saturation",
		.name		= "Saturation",
@@ -225,15 +228,16 @@ static struct v4l2_queryctrl controls[] = {
		.step		= 1,
		.step		= 1,
		.default_value	= 64,
		.default_value	= 64,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.type		= V4L2_CTRL_TYPE_INTEGER,
		.flags 		= V4L2_CTRL_FLAG_SLIDER,
	},{
	},{
		.id		= V4L2_CID_VFLIP,
		.id		= V4L2_CID_VFLIP,
		.name		= "Vertical flip",
		.name		= "Vertical Flip",
		.minimum	= 0,
		.minimum	= 0,
		.maximum	= 1,
		.maximum	= 1,
		.type		= V4L2_CTRL_TYPE_BOOLEAN,
		.type		= V4L2_CTRL_TYPE_BOOLEAN,
	},{
	},{
		.id		= V4L2_CID_HFLIP,
		.id		= V4L2_CID_HFLIP,
		.name		= "Horizontal flip",
		.name		= "Horizontal Flip",
		.minimum	= 0,
		.minimum	= 0,
		.maximum	= 1,
		.maximum	= 1,
		.type		= V4L2_CTRL_TYPE_BOOLEAN,
		.type		= V4L2_CTRL_TYPE_BOOLEAN,
@@ -1112,6 +1116,22 @@ static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type ty
	return err;
	return err;
}
}


static int vidioc_g_chip_ident(struct file *file, void *__fh,
		struct v4l2_dbg_chip_ident *chip)
{
	struct saa7146_fh *fh = __fh;
	struct saa7146_dev *dev = fh->dev;

	chip->ident = V4L2_IDENT_NONE;
	chip->revision = 0;
	if (v4l2_chip_match_host(&chip->match)) {
		chip->ident = V4L2_IDENT_SAA7146;
		return 0;
	}
	return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
			core, g_chip_ident, chip);
}

#ifdef CONFIG_VIDEO_V4L1_COMPAT
#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
{
{
@@ -1152,6 +1172,7 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
	.vidioc_try_fmt_vid_overlay  = vidioc_try_fmt_vid_overlay,
	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
	.vidioc_s_fmt_vid_overlay    = vidioc_s_fmt_vid_overlay,
	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,
	.vidioc_g_chip_ident         = vidioc_g_chip_ident,


	.vidioc_overlay 	     = vidioc_overlay,
	.vidioc_overlay 	     = vidioc_overlay,
	.vidioc_g_fbuf  	     = vidioc_g_fbuf,
	.vidioc_g_fbuf  	     = vidioc_g_fbuf,
+109 −165
Original line number Original line Diff line number Diff line
@@ -32,9 +32,14 @@
#include "mxb.h"
#include "mxb.h"
#include "tea6415c.h"
#include "tea6415c.h"
#include "tea6420.h"
#include "tea6420.h"
#include "tda9840.h"


#define I2C_SAA7111 0x24
#define	I2C_SAA5246A  0x11
#define I2C_SAA7111A  0x24
#define	I2C_TDA9840   0x42
#define	I2C_TEA6415C  0x43
#define	I2C_TEA6420_1 0x4c
#define	I2C_TEA6420_2 0x4d
#define	I2C_TUNER     0x60


#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)
#define MXB_BOARD_CAN_DO_VBI(dev)   (dev->revision != 0)


@@ -79,30 +84,28 @@ static struct {
static int video_audio_connect[MXB_INPUTS] =
static int video_audio_connect[MXB_INPUTS] =
	{ 0, 1, 3, 3 };
	{ 0, 1, 3, 3 };


/* these are the necessary input-output-pins for bringing one audio source
/* These are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output */
   (see above) to the CD-output. Note that gain is set to 0 in this table. */
static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] =
static struct v4l2_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
		{
	{ { 1, 1 }, { 1, 1 } },	/* Tuner */
		{{1,1,0},{1,1,0}},	/* Tuner */
	{ { 5, 1 }, { 6, 1 } },	/* AUX 1 */
		{{5,1,0},{6,1,0}},	/* AUX 1 */
	{ { 4, 1 }, { 6, 1 } },	/* AUX 2 */
		{{4,1,0},{6,1,0}},	/* AUX 2 */
	{ { 3, 1 }, { 6, 1 } },	/* AUX 3 */
		{{3,1,0},{6,1,0}},	/* AUX 3 */
	{ { 1, 1 }, { 3, 1 } },	/* Radio */
		{{1,1,0},{3,1,0}},	/* Radio */
	{ { 1, 1 }, { 2, 1 } },	/* CD-Rom */
		{{1,1,0},{2,1,0}},	/* CD-Rom */
	{ { 6, 1 }, { 6, 1 } }	/* Mute */
		{{6,1,0},{6,1,0}}	/* Mute */
};
};


/* these are the necessary input-output-pins for bringing one audio source
/* These are the necessary input-output-pins for bringing one audio source
(see above) to the line-output */
   (see above) to the line-output. Note that gain is set to 0 in this table. */
static struct tea6420_multiplex TEA6420_line[MXB_AUDIOS+1][2] =
static struct v4l2_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
		{
	{ { 2, 3 }, { 1, 2 } },
		{{2,3,0},{1,2,0}},
	{ { 5, 3 }, { 6, 2 } },
		{{5,3,0},{6,2,0}},
	{ { 4, 3 }, { 6, 2 } },
		{{4,3,0},{6,2,0}},
	{ { 3, 3 }, { 6, 2 } },
		{{3,3,0},{6,2,0}},
	{ { 2, 3 }, { 3, 2 } },
		{{2,3,0},{3,2,0}},
	{ { 2, 3 }, { 2, 2 } },
		{{2,3,0},{2,2,0}},
	{ { 6, 3 }, { 6, 2 } }	/* Mute */
		{{6,3,0},{6,2,0}}	/* Mute */
};
};


#define MAXCONTROLS	1
#define MAXCONTROLS	1
@@ -117,12 +120,12 @@ struct mxb


	struct i2c_adapter	i2c_adapter;
	struct i2c_adapter	i2c_adapter;


	struct i2c_client	*saa7111a;
	struct v4l2_subdev	*saa7111a;
	struct i2c_client	*tda9840;
	struct v4l2_subdev	*tda9840;
	struct i2c_client	*tea6415c;
	struct v4l2_subdev	*tea6415c;
	struct i2c_client	*tuner;
	struct v4l2_subdev	*tuner;
	struct i2c_client	*tea6420_1;
	struct v4l2_subdev	*tea6420_1;
	struct i2c_client	*tea6420_2;
	struct v4l2_subdev	*tea6420_2;


	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
	int	cur_mode;	/* current audio mode (mono, stereo, ...) */
	int	cur_input;	/* current input */
	int	cur_input;	/* current input */
@@ -130,73 +133,33 @@ struct mxb
	struct v4l2_frequency	cur_freq;	/* current frequency the tuner is tuned to */
	struct v4l2_frequency	cur_freq;	/* current frequency the tuner is tuned to */
};
};


static struct saa7146_extension extension;
#define saa7111a_call(mxb, o, f, args...) \

	v4l2_subdev_call(mxb->saa7111a, o, f, ##args)
static int mxb_check_clients(struct device *dev, void *data)
#define tea6420_1_call(mxb, o, f, args...) \
{
	v4l2_subdev_call(mxb->tea6420_1, o, f, ##args)
	struct mxb *mxb = data;
#define tea6420_2_call(mxb, o, f, args...) \
	struct i2c_client *client = i2c_verify_client(dev);
	v4l2_subdev_call(mxb->tea6420_2, o, f, ##args)
#define tda9840_call(mxb, o, f, args...) \
	v4l2_subdev_call(mxb->tda9840, o, f, ##args)
#define tea6415c_call(mxb, o, f, args...) \
	v4l2_subdev_call(mxb->tea6415c, o, f, ##args)
#define tuner_call(mxb, o, f, args...) \
	v4l2_subdev_call(mxb->tuner, o, f, ##args)
#define call_all(dev, o, f, args...) \
	v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)


	if (!client)
static struct saa7146_extension extension;
		return 0;

	if (I2C_ADDR_TEA6420_1 == client->addr)
		mxb->tea6420_1 = client;
	if (I2C_ADDR_TEA6420_2 == client->addr)
		mxb->tea6420_2 = client;
	if (I2C_TEA6415C_2 == client->addr)
		mxb->tea6415c = client;
	if (I2C_ADDR_TDA9840 == client->addr)
		mxb->tda9840 = client;
	if (I2C_SAA7111 == client->addr)
		mxb->saa7111a = client;
	if (0x60 == client->addr)
		mxb->tuner = client;

	return 0;
}


static int mxb_probe(struct saa7146_dev *dev)
static int mxb_probe(struct saa7146_dev *dev)
{
{
	struct mxb *mxb = NULL;
	struct mxb *mxb = NULL;
	int result;

	result = request_module("saa7115");
	if (result < 0) {
		printk("mxb: saa7111 i2c module not available.\n");
		return -ENODEV;
	}
	result = request_module("tea6420");
	if (result < 0) {
		printk("mxb: tea6420 i2c module not available.\n");
		return -ENODEV;
	}
	result = request_module("tea6415c");
	if (result < 0) {
		printk("mxb: tea6415c i2c module not available.\n");
		return -ENODEV;
	}
	result = request_module("tda9840");
	if (result < 0) {
		printk("mxb: tda9840 i2c module not available.\n");
		return -ENODEV;
	}
	result = request_module("tuner");
	if (result < 0) {
		printk("mxb: tuner i2c module not available.\n");
		return -ENODEV;
	}


	mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
	mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
	if( NULL == mxb ) {
	if (mxb == NULL) {
		DEB_D(("not enough kernel memory.\n"));
		DEB_D(("not enough kernel memory.\n"));
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	mxb->i2c_adapter = (struct i2c_adapter) {
		.class = I2C_CLASS_TV_ANALOG,
	};

	snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
	snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);


	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
	saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
@@ -206,8 +169,15 @@ static int mxb_probe(struct saa7146_dev* dev)
		return -EFAULT;
		return -EFAULT;
	}
	}


	/* loop through all i2c-devices on the bus and look who is there */
	mxb->saa7111a = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa7115", "saa7111", I2C_SAA7111A);
	device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
	mxb->tea6420_1 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_1);
	mxb->tea6420_2 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6420", "tea6420", I2C_TEA6420_2);
	mxb->tea6415c = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tea6415c", "tea6415c", I2C_TEA6415C);
	mxb->tda9840 = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tda9840", "tda9840", I2C_TDA9840);
	mxb->tuner = v4l2_i2c_new_subdev(&mxb->i2c_adapter, "tuner", "tuner", I2C_TUNER);
	if (v4l2_i2c_new_subdev(&mxb->i2c_adapter, "saa5246a", "saa5246a", I2C_SAA5246A)) {
		printk(KERN_INFO "mxb: found teletext decoder\n");
	}


	/* check if all devices are present */
	/* check if all devices are present */
	if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
	if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
@@ -295,47 +265,45 @@ static int mxb_init_done(struct saa7146_dev* dev)
	struct v4l2_routing route;
	struct v4l2_routing route;


	int i = 0, err = 0;
	int i = 0, err = 0;
	struct tea6415c_multiplex vm;


	/* select video mode in saa7111a */
	/* select video mode in saa7111a */
	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_S_STD, &std);
	saa7111a_call(mxb, tuner, s_std, std);


	/* select tuner-output on saa7111a */
	/* select tuner-output on saa7111a */
	i = 0;
	i = 0;
	route.input = SAA7115_COMPOSITE0;
	route.input = SAA7115_COMPOSITE0;
	route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
	route.output = SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS;
	mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route);
	saa7111a_call(mxb, video, s_routing, &route);


	/* select a tuner type */
	/* select a tuner type */
	tun_setup.mode_mask = T_ANALOG_TV;
	tun_setup.mode_mask = T_ANALOG_TV;
	tun_setup.addr = ADDR_UNSET;
	tun_setup.addr = ADDR_UNSET;
	tun_setup.type = TUNER_PHILIPS_PAL;
	tun_setup.type = TUNER_PHILIPS_PAL;
	mxb->tuner->driver->command(mxb->tuner, TUNER_SET_TYPE_ADDR, &tun_setup);
	tuner_call(mxb, tuner, s_type_addr, &tun_setup);
	/* tune in some frequency on tuner */
	/* tune in some frequency on tuner */
	mxb->cur_freq.tuner = 0;
	mxb->cur_freq.tuner = 0;
	mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
	mxb->cur_freq.type = V4L2_TUNER_ANALOG_TV;
	mxb->cur_freq.frequency = freq;
	mxb->cur_freq.frequency = freq;
	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY,
	tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
					&mxb->cur_freq);


	/* set a default video standard */
	/* set a default video standard */
	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
	tuner_call(mxb, tuner, s_std, std);


	/* mute audio on tea6420s */
	/* mute audio on tea6420s */
	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[6][0]);
	tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[6][1]);
	tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);
	mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[6][0]);
	tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[6][0]);
	mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[6][1]);
	tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[6][1]);


	/* switch to tuner-channel on tea6415c */
	/* switch to tuner-channel on tea6415c */
	vm.out = 17;
	route.input = 3;
	vm.in  = 3;
	route.output = 17;
	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
	tea6415c_call(mxb, video, s_routing, &route);


	/* select tuner-output on multicable on tea6415c */
	/* select tuner-output on multicable on tea6415c */
	vm.in  = 3;
	route.input = 3;
	vm.out = 13;
	route.output = 13;
	mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm);
	tea6415c_call(mxb, video, s_routing, &route);


	/* the rest for mxb */
	/* the rest for mxb */
	mxb->cur_input = 0;
	mxb->cur_input = 0;
@@ -461,14 +429,14 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
		mxb->cur_mute = vc->value;
		mxb->cur_mute = vc->value;
		if (!vc->value) {
		if (!vc->value) {
			/* switch the audio-source */
			/* switch the audio-source */
			mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
			tea6420_1_call(mxb, audio, s_routing,
					&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
					&TEA6420_line[video_audio_connect[mxb->cur_input]][0]);
			mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
			tea6420_2_call(mxb, audio, s_routing,
					&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
					&TEA6420_line[video_audio_connect[mxb->cur_input]][1]);
		} else {
		} else {
			mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
			tea6420_1_call(mxb, audio, s_routing,
					&TEA6420_line[6][0]);
					&TEA6420_line[6][0]);
			mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
			tea6420_2_call(mxb, audio, s_routing,
					&TEA6420_line[6][1]);
					&TEA6420_line[6][1]);
		}
		}
		DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
		DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value));
@@ -499,7 +467,6 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
{
{
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
	struct mxb *mxb = (struct mxb *)dev->ext_priv;
	struct tea6415c_multiplex vm;
	struct v4l2_routing route;
	struct v4l2_routing route;
	int i = 0;
	int i = 0;


@@ -518,16 +485,16 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
	switch (input) {
	switch (input) {
	case TUNER:
	case TUNER:
		i = SAA7115_COMPOSITE0;
		i = SAA7115_COMPOSITE0;
		vm.in  = 3;
		route.input = 3;
		vm.out = 17;
		route.output = 17;


		if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
		if (tea6415c_call(mxb, video, s_routing, &route)) {
			printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
			printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n");
			return -EFAULT;
			return -EFAULT;
		}
		}
		/* connect tuner-output always to multicable */
		/* connect tuner-output always to multicable */
		vm.in  = 3;
		route.input = 3;
		vm.out = 13;
		route.output = 13;
		break;
		break;
	case AUX3_YC:
	case AUX3_YC:
		/* nothing to be done here. aux3_yc is
		/* nothing to be done here. aux3_yc is
@@ -541,8 +508,8 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
		break;
		break;
	case AUX1:
	case AUX1:
		i = SAA7115_COMPOSITE0;
		i = SAA7115_COMPOSITE0;
		vm.in  = 1;
		route.input = 1;
		vm.out = 17;
		route.output = 17;
		break;
		break;
	}
	}


@@ -550,7 +517,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
	switch (input) {
	switch (input) {
	case TUNER:
	case TUNER:
	case AUX1:
	case AUX1:
		if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) {
		if (tea6415c_call(mxb, video, s_routing, &route)) {
			printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
			printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n");
			return -EFAULT;
			return -EFAULT;
		}
		}
@@ -562,14 +529,14 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
	/* switch video in saa7111a */
	/* switch video in saa7111a */
	route.input = i;
	route.input = i;
	route.output = 0;
	route.output = 0;
	if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route))
	if (saa7111a_call(mxb, video, s_routing, &route))
		printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");
		printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n");


	/* switch the audio-source only if necessary */
	/* switch the audio-source only if necessary */
	if (0 == mxb->cur_mute) {
	if (0 == mxb->cur_mute) {
		mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH,
		tea6420_1_call(mxb, audio, s_routing,
				&TEA6420_line[video_audio_connect[input]][0]);
				&TEA6420_line[video_audio_connect[input]][0]);
		mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH,
		tea6420_2_call(mxb, audio, s_routing,
				&TEA6420_line[video_audio_connect[input]][1]);
				&TEA6420_line[video_audio_connect[input]][1]);
	}
	}


@@ -589,14 +556,12 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
	DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));
	DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index));


	memset(t, 0, sizeof(*t));
	memset(t, 0, sizeof(*t));
	i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t);

	strlcpy(t->name, "TV Tuner", sizeof(t->name));
	strlcpy(t->name, "TV Tuner", sizeof(t->name));
	t->type = V4L2_TUNER_ANALOG_TV;
	t->type = V4L2_TUNER_ANALOG_TV;
	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
	t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
	t->audmode = mxb->cur_mode;
	t->audmode = mxb->cur_mode;
	return 0;
	return call_all(dev, tuner, g_tuner, t);
}
}


static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
@@ -610,8 +575,7 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
	}
	}


	mxb->cur_mode = t->audmode;
	mxb->cur_mode = t->audmode;
	i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t);
	return call_all(dev, tuner, s_tuner, t);
	return 0;
}
}


static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
@@ -652,7 +616,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
	DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));
	DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency));


	/* tune in desired frequency */
	/* tune in desired frequency */
	mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq);
	tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);


	/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
	/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
	spin_lock(&dev->slock);
	spin_lock(&dev->slock);
@@ -687,19 +651,15 @@ static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
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 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 call_all(dev, core, g_register, reg);
	return 0;
}
}


static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
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 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 call_all(dev, core, s_register, reg);
	return 0;
}
}
#endif
#endif


@@ -720,8 +680,8 @@ static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)


		DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));
		DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i));


		mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]);
		tea6420_1_call(mxb, audio, s_routing, &TEA6420_cd[i][0]);
		mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]);
		tea6420_2_call(mxb, audio, s_routing, &TEA6420_cd[i][1]);


		return 0;
		return 0;
	}
	}
@@ -735,8 +695,8 @@ static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
		}
		}


		DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
		DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i));
		mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]);
		tea6420_1_call(mxb, audio, s_routing, &TEA6420_line[i][0]);
		mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]);
		tea6420_2_call(mxb, audio, s_routing, &TEA6420_line[i][1]);


		return 0;
		return 0;
	}
	}
@@ -791,13 +751,6 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
		}
		}
	}
	}


	i2c_use_client(mxb->tea6420_1);
	i2c_use_client(mxb->tea6420_2);
	i2c_use_client(mxb->tea6415c);
	i2c_use_client(mxb->tda9840);
	i2c_use_client(mxb->saa7111a);
	i2c_use_client(mxb->tuner);

	printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);
	printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num);


	mxb_num++;
	mxb_num++;
@@ -811,13 +764,6 @@ static int mxb_detach(struct saa7146_dev *dev)


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


	i2c_release_client(mxb->tea6420_1);
	i2c_release_client(mxb->tea6420_2);
	i2c_release_client(mxb->tea6415c);
	i2c_release_client(mxb->tda9840);
	i2c_release_client(mxb->saa7111a);
	i2c_release_client(mxb->tuner);

	saa7146_unregister_device(&mxb->video_dev,dev);
	saa7146_unregister_device(&mxb->video_dev,dev);
	if (MXB_BOARD_CAN_DO_VBI(dev))
	if (MXB_BOARD_CAN_DO_VBI(dev))
		saa7146_unregister_device(&mxb->vbi_dev, dev);
		saa7146_unregister_device(&mxb->vbi_dev, dev);
@@ -834,8 +780,6 @@ static int mxb_detach(struct saa7146_dev *dev)
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;
	int zero = 0;
	int one = 1;


	if (V4L2_STD_PAL_I == standard->id) {
	if (V4L2_STD_PAL_I == standard->id) {
		v4l2_std_id std = V4L2_STD_PAL_I;
		v4l2_std_id std = V4L2_STD_PAL_I;
@@ -844,8 +788,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
		/* set the 7146 gpio register -- I don't know what this does exactly */
		/* set the 7146 gpio register -- I don't know what this does exactly */
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
		/* unset the 7111 gpio register -- I don't know what this does exactly */
		/* unset the 7111 gpio register -- I don't know what this does exactly */
		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &zero);
		saa7111a_call(mxb, core, s_gpio, 0);
		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
		tuner_call(mxb, tuner, s_std, std);
	} else {
	} else {
		v4l2_std_id std = V4L2_STD_PAL_BG;
		v4l2_std_id std = V4L2_STD_PAL_BG;


@@ -853,8 +797,8 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
		/* set the 7146 gpio register -- I don't know what this does exactly */
		/* set the 7146 gpio register -- I don't know what this does exactly */
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
		saa7146_write(dev, GPIO_CTRL, 0x00404050);
		/* set the 7111 gpio register -- I don't know what this does exactly */
		/* set the 7111 gpio register -- I don't know what this does exactly */
		mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_GPIO, &one);
		saa7111a_call(mxb, core, s_gpio, 1);
		mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std);
		tuner_call(mxb, tuner, s_std, std);
	}
	}
	return 0;
	return 0;
}
}
+45 −24
Original line number Original line Diff line number Diff line
@@ -46,10 +46,11 @@
#include <linux/smp_lock.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/videotext.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-i2c-drv.h>


MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
@@ -388,13 +389,19 @@ MODULE_LICENSE("GPL");


struct saa5246a_device
struct saa5246a_device
{
{
	struct v4l2_subdev sd;
	struct video_device *vdev;
	u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
	u8     pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
	int    is_searching[NUM_DAUS];
	int    is_searching[NUM_DAUS];
	struct i2c_client *client;
	unsigned long in_use;
	unsigned long in_use;
	struct mutex lock;
	struct mutex lock;
};
};


static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
{
	return container_of(sd, struct saa5246a_device, sd);
}

static struct video_device saa_template;	/* Declared near bottom */
static struct video_device saa_template;	/* Declared near bottom */


/*
/*
@@ -403,12 +410,13 @@ static struct video_device saa_template; /* Declared near bottom */


static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
{
{
	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
	char buf[64];
	char buf[64];


	buf[0] = reg;
	buf[0] = reg;
	memcpy(buf+1, data, count);
	memcpy(buf+1, data, count);


	if(i2c_master_send(t->client, buf, count+1)==count+1)
	if (i2c_master_send(client, buf, count + 1) == count + 1)
		return 0;
		return 0;
	return -1;
	return -1;
}
}
@@ -436,7 +444,9 @@ static int i2c_senddata(struct saa5246a_device *t, ...)
 */
 */
static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
{
{
	if(i2c_master_recv(t->client, buf, count)!=count)
	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);

	if (i2c_master_recv(client, buf, count) != count)
		return -1;
		return -1;
	return 0;
	return 0;
}
}
@@ -961,9 +971,6 @@ static int saa5246a_open(struct file *file)
{
{
	struct saa5246a_device *t = video_drvdata(file);
	struct saa5246a_device *t = video_drvdata(file);


	if (t->client == NULL)
		return -ENODEV;

	if (test_and_set_bit(0, &t->in_use))
	if (test_and_set_bit(0, &t->in_use))
		return -EBUSY;
		return -EBUSY;


@@ -1033,18 +1040,29 @@ static struct video_device saa_template =
	.minor    = -1,
	.minor    = -1,
};
};


/* Addresses to scan */
static int saa5246a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);

	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5246A, 0);
}

static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
	.g_chip_ident = saa5246a_g_chip_ident,
};

static const struct v4l2_subdev_ops saa5246a_ops = {
	.core = &saa5246a_core_ops,
};


I2C_CLIENT_INSMOD;


static int saa5246a_probe(struct i2c_client *client,
static int saa5246a_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
			const struct i2c_device_id *id)
{
{
	int pgbuf;
	int pgbuf;
	int err;
	int err;
	struct video_device *vd;
	struct saa5246a_device *t;
	struct saa5246a_device *t;
	struct v4l2_subdev *sd;


	v4l_info(client, "chip found @ 0x%x (%s)\n",
	v4l_info(client, "chip found @ 0x%x (%s)\n",
			client->addr << 1, client->adapter->name);
			client->addr << 1, client->adapter->name);
@@ -1053,40 +1071,43 @@ static int saa5246a_probe(struct i2c_client *client,
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	if (t == NULL)
	if (t == NULL)
		return -ENOMEM;
		return -ENOMEM;
	sd = &t->sd;
	v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
	mutex_init(&t->lock);
	mutex_init(&t->lock);


	/* Now create a video4linux device */
	/* Now create a video4linux device */
	vd = video_device_alloc();
	t->vdev = video_device_alloc();
	if (vd == NULL) {
	if (t->vdev == NULL) {
		kfree(t);
		kfree(t);
		return -ENOMEM;
		return -ENOMEM;
	}
	}
	i2c_set_clientdata(client, vd);
	memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
	memcpy(vd, &saa_template, sizeof(*vd));


	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
		memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
		memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
		t->is_searching[pgbuf] = false;
		t->is_searching[pgbuf] = false;
	}
	}
	video_set_drvdata(vd, t);
	video_set_drvdata(t->vdev, t);


	/* Register it */
	/* Register it */
	err = video_register_device(vd, VFL_TYPE_VTX, -1);
	err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
	if (err < 0) {
	if (err < 0) {
		kfree(t);
		kfree(t);
		video_device_release(vd);
		video_device_release(t->vdev);
		t->vdev = NULL;
		return err;
		return err;
	}
	}
	t->client = client;
	return 0;
	return 0;
}
}


static int saa5246a_remove(struct i2c_client *client)
static int saa5246a_remove(struct i2c_client *client)
{
{
	struct video_device *vd = i2c_get_clientdata(client);
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct saa5246a_device *t = to_dev(sd);


	video_unregister_device(vd);
	video_unregister_device(t->vdev);
	kfree(video_get_drvdata(vd));
	v4l2_device_unregister_subdev(sd);
	kfree(t);
	return 0;
	return 0;
}
}


+45 −25
Original line number Original line Diff line number Diff line
@@ -50,15 +50,17 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/videotext.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-i2c-drv-legacy.h>
#include <media/v4l2-i2c-drv.h>


MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");



#define VTX_VER_MAJ 1
#define VTX_VER_MAJ 1
#define VTX_VER_MIN 8
#define VTX_VER_MIN 8


@@ -95,17 +97,23 @@ typedef struct {


struct saa5249_device
struct saa5249_device
{
{
	struct v4l2_subdev sd;
	struct video_device *vdev;
	vdau_t vdau[NUM_DAUS];			/* Data for virtual DAUs (the 5249 only has one */
	vdau_t vdau[NUM_DAUS];			/* Data for virtual DAUs (the 5249 only has one */
						/* real DAU, so we have to simulate some more) */
						/* real DAU, so we have to simulate some more) */
	int vtx_use_count;
	int vtx_use_count;
	int is_searching[NUM_DAUS];
	int is_searching[NUM_DAUS];
	int disp_mode;
	int disp_mode;
	int virtual_mode;
	int virtual_mode;
	struct i2c_client *client;
	unsigned long in_use;
	unsigned long in_use;
	struct mutex lock;
	struct mutex lock;
};
};


static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
{
	return container_of(sd, struct saa5249_device, sd);
}



#define CCTWR 34		/* IC write/read-address of vtx-chip */
#define CCTWR 34		/* IC write/read-address of vtx-chip */
#define CCTRD 35
#define CCTRD 35
@@ -147,12 +155,13 @@ static void jdelay(unsigned long delay)


static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
{
{
	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
	char buf[64];
	char buf[64];


	buf[0] = reg;
	buf[0] = reg;
	memcpy(buf+1, data, count);
	memcpy(buf+1, data, count);


	if (i2c_master_send(t->client, buf, count + 1) == count + 1)
	if (i2c_master_send(client, buf, count + 1) == count + 1)
		return 0;
		return 0;
	return -1;
	return -1;
}
}
@@ -180,7 +189,9 @@ static int i2c_senddata(struct saa5249_device *t, ...)


static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
{
{
	if(i2c_master_recv(t->client, buf, count)!=count)
	struct i2c_client *client = v4l2_get_subdevdata(&t->sd);

	if (i2c_master_recv(client, buf, count) != count)
		return -1;
		return -1;
	return 0;
	return 0;
}
}
@@ -497,9 +508,6 @@ static int saa5249_open(struct file *file)
	struct saa5249_device *t = video_drvdata(file);
	struct saa5249_device *t = video_drvdata(file);
	int pgbuf;
	int pgbuf;


	if (t->client == NULL)
		return -ENODEV;

	if (test_and_set_bit(0, &t->in_use))
	if (test_and_set_bit(0, &t->in_use))
		return -EBUSY;
		return -EBUSY;


@@ -553,18 +561,28 @@ static struct video_device saa_template =
	.release 	= video_device_release,
	.release 	= video_device_release,
};
};


/* Addresses to scan */
static int saa5249_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END };
{
	struct i2c_client *client = v4l2_get_subdevdata(sd);


I2C_CLIENT_INSMOD;
	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_SAA5249, 0);
}

static const struct v4l2_subdev_core_ops saa5249_core_ops = {
	.g_chip_ident = saa5249_g_chip_ident,
};

static const struct v4l2_subdev_ops saa5249_ops = {
	.core = &saa5249_core_ops,
};


static int saa5249_probe(struct i2c_client *client,
static int saa5249_probe(struct i2c_client *client,
			const struct i2c_device_id *id)
			const struct i2c_device_id *id)
{
{
	int pgbuf;
	int pgbuf;
	int err;
	int err;
	struct video_device *vd;
	struct saa5249_device *t;
	struct saa5249_device *t;
	struct v4l2_subdev *sd;


	v4l_info(client, "chip found @ 0x%x (%s)\n",
	v4l_info(client, "chip found @ 0x%x (%s)\n",
			client->addr << 1, client->adapter->name);
			client->addr << 1, client->adapter->name);
@@ -573,16 +591,17 @@ static int saa5249_probe(struct i2c_client *client,
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	t = kzalloc(sizeof(*t), GFP_KERNEL);
	if (t == NULL)
	if (t == NULL)
		return -ENOMEM;
		return -ENOMEM;
	sd = &t->sd;
	v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
	mutex_init(&t->lock);
	mutex_init(&t->lock);


	/* Now create a video4linux device */
	/* Now create a video4linux device */
	vd = kmalloc(sizeof(struct video_device), GFP_KERNEL);
	t->vdev = video_device_alloc();
	if (vd == NULL) {
	if (t->vdev == NULL) {
		kfree(client);
		kfree(client);
		return -ENOMEM;
		return -ENOMEM;
	}
	}
	i2c_set_clientdata(client, vd);
	memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
	memcpy(vd, &saa_template, sizeof(*vd));


	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
	for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
		memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
@@ -593,26 +612,27 @@ static int saa5249_probe(struct i2c_client *client,
		t->vdau[pgbuf].stopped = true;
		t->vdau[pgbuf].stopped = true;
		t->is_searching[pgbuf] = false;
		t->is_searching[pgbuf] = false;
	}
	}
	video_set_drvdata(vd, t);
	video_set_drvdata(t->vdev, t);


	/* Register it */
	/* Register it */
	err = video_register_device(vd, VFL_TYPE_VTX, -1);
	err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
	if (err < 0) {
	if (err < 0) {
		kfree(t);
		kfree(t);
		kfree(vd);
		video_device_release(t->vdev);
		t->vdev = NULL;
		return err;
		return err;
	}
	}
	t->client = client;
	return 0;
	return 0;
}
}


static int saa5249_remove(struct i2c_client *client)
static int saa5249_remove(struct i2c_client *client)
{
{
	struct video_device *vd = i2c_get_clientdata(client);
	struct v4l2_subdev *sd = i2c_get_clientdata(client);
	struct saa5249_device *t = to_dev(sd);


	video_unregister_device(vd);
	video_unregister_device(t->vdev);
	kfree(video_get_drvdata(vd));
	v4l2_device_unregister_subdev(sd);
	kfree(vd);
	kfree(t);
	return 0;
	return 0;
}
}


+9 −72

File changed.

Preview size limit exceeded, changes collapsed.

Loading