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

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

[media] ivtv: implement new decoder controls

parent 77bd4c0f
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "ivtv-driver.h"
#include "ivtv-ioctl.h"
#include "ivtv-controls.h"
#include "ivtv-mailbox.h"

static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
{
@@ -99,3 +100,64 @@ struct cx2341x_handler_ops ivtv_cxhdl_ops = {
	.s_video_encoding = ivtv_s_video_encoding,
	.s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
};

int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame)
{
	u32 data[CX2341X_MBOX_MAX_DATA];

	if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
		*pts = (s64)((u64)itv->last_dec_timing[2] << 32) |
			(u64)itv->last_dec_timing[1];
		*frame = itv->last_dec_timing[0];
		return 0;
	}
	*pts = 0;
	*frame = 0;
	if (atomic_read(&itv->decoding)) {
		if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
			IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
			return -EIO;
		}
		memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
		set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
		*pts = (s64)((u64) data[2] << 32) | (u64) data[1];
		*frame = data[0];
		/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
	}
	return 0;
}

static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, hdl_out);

	switch (ctrl->id) {
	/* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
	   control cluster */
	case V4L2_CID_MPEG_VIDEO_DEC_PTS:
		return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
					     &itv->ctrl_frame->val64);
	}
	return 0;
}

static int ivtv_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct ivtv *itv = container_of(ctrl->handler, struct ivtv, hdl_out);

	switch (ctrl->id) {
	/* V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK and MULTILINGUAL_PLAYBACK
	   control cluster */
	case V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK:
		itv->audio_stereo_mode = itv->ctrl_audio_playback->val - 1;
		itv->audio_bilingual_mode = itv->ctrl_audio_multilingual_playback->val - 1;
		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
		break;
	}
	return 0;
}

const struct v4l2_ctrl_ops ivtv_hdl_out_ops = {
	.s_ctrl = ivtv_s_ctrl,
	.g_volatile_ctrl = ivtv_g_volatile_ctrl,
};
+2 −0
Original line number Diff line number Diff line
@@ -22,5 +22,7 @@
#define IVTV_CONTROLS_H

extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);

#endif
+33 −2
Original line number Diff line number Diff line
@@ -744,8 +744,6 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)

	itv->cur_dma_stream = -1;
	itv->cur_pio_stream = -1;
	itv->audio_stereo_mode = AUDIO_STEREO;
	itv->audio_bilingual_mode = AUDIO_MONO_LEFT;

	/* Ctrls */
	itv->speed = 1000;
@@ -1200,6 +1198,32 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
	itv->tuner_std = itv->std;

	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
		v4l2_ctrl_handler_init(&itv->hdl_out, 50);
		itv->ctrl_pts = v4l2_ctrl_new_std(&itv->hdl_out, &ivtv_hdl_out_ops,
				V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
		itv->ctrl_frame = v4l2_ctrl_new_std(&itv->hdl_out, &ivtv_hdl_out_ops,
				V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
		/* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
		   mask that menu item. */
		itv->ctrl_audio_playback =
			v4l2_ctrl_new_std_menu(&itv->hdl_out, &ivtv_hdl_out_ops,
				V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK,
				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
				V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO);
		itv->ctrl_audio_multilingual_playback =
			v4l2_ctrl_new_std_menu(&itv->hdl_out, &ivtv_hdl_out_ops,
				V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK,
				V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO,
				1 << V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO,
				V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT);
		v4l2_ctrl_add_handler(&itv->hdl_out, &itv->cxhdl.hdl);
		if (itv->hdl_out.error) {
			retval = itv->hdl_out.error;
			goto free_i2c;
		}
		v4l2_ctrl_cluster(2, &itv->ctrl_pts);
		v4l2_ctrl_cluster(2, &itv->ctrl_audio_playback);
		ivtv_call_all(itv, video, s_std_output, itv->std);
		/* Turn off the output signal. The mpeg decoder is not yet
		   active so without this you would get a green image until the
@@ -1236,6 +1260,9 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
free_irq:
	free_irq(itv->pdev->irq, (void *)itv);
free_i2c:
	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
		v4l2_ctrl_handler_free(&itv->hdl_out);
	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
	exit_ivtv_i2c(itv);
free_io:
	ivtv_iounmap(itv);
@@ -1391,6 +1418,10 @@ static void ivtv_remove(struct pci_dev *pdev)
	ivtv_streams_cleanup(itv, 1);
	ivtv_udma_free(itv);

	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
		v4l2_ctrl_handler_free(&itv->hdl_out);
	v4l2_ctrl_handler_free(&itv->cxhdl.hdl);

	exit_ivtv_i2c(itv);

	free_irq(itv->pdev->irq, (void *)itv);
+11 −1
Original line number Diff line number Diff line
@@ -631,6 +631,17 @@ struct ivtv {

	struct v4l2_device v4l2_dev;
	struct cx2341x_handler cxhdl;
	struct {
		/* PTS/Frame count control cluster */
		struct v4l2_ctrl *ctrl_pts;
		struct v4l2_ctrl *ctrl_frame;
	};
	struct {
		/* Audio Playback control cluster */
		struct v4l2_ctrl *ctrl_audio_playback;
		struct v4l2_ctrl *ctrl_audio_multilingual_playback;
	};
	struct v4l2_ctrl_handler hdl_out;
	struct v4l2_ctrl_handler hdl_gpio;
	struct v4l2_subdev sd_gpio;	/* GPIO sub-device */
	u16 instance;
@@ -650,7 +661,6 @@ struct ivtv {
	u8 audio_stereo_mode;           /* decoder setting how to handle stereo MPEG audio */
	u8 audio_bilingual_mode;        /* decoder setting how to handle bilingual MPEG audio */


	/* Locking */
	spinlock_t lock;                /* lock access to this struct */
	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
+12 −55
Original line number Diff line number Diff line
@@ -1510,13 +1510,6 @@ static int ivtv_log_status(struct file *file, void *fh)
			"YUV Frames",
			"Passthrough",
		};
		static const char * const audio_modes[5] = {
			"Stereo",
			"Left",
			"Right",
			"Mono",
			"Swapped"
		};
		static const char * const alpha_mode[4] = {
			"None",
			"Global",
@@ -1545,9 +1538,6 @@ static int ivtv_log_status(struct file *file, void *fh)
		ivtv_get_output(itv, itv->active_output, &vidout);
		ivtv_get_audio_output(itv, 0, &audout);
		IVTV_INFO("Video Output: %s\n", vidout.name);
		IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
			audio_modes[itv->audio_stereo_mode],
			audio_modes[itv->audio_bilingual_mode]);
		if (mode < 0 || mode > OUT_PASSTHROUGH)
			mode = OUT_NONE;
		IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
@@ -1560,6 +1550,9 @@ static int ivtv_log_status(struct file *file, void *fh)
	}
	IVTV_INFO("Tuner:  %s\n",
		test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
		v4l2_ctrl_handler_log_status(&itv->hdl_out, itv->v4l2_dev.name);
	else
		v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.name);
	IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
	for (i = 0; i < IVTV_MAX_STREAMS; i++) {
@@ -1633,8 +1626,8 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
	}

	case VIDEO_GET_PTS: {
		u32 data[CX2341X_MBOX_MAX_DATA];
		u64 *pts = arg;
		s64 *pts = arg;
		s64 frame;

		IVTV_DEBUG_IOCTL("VIDEO_GET_PTS\n");
		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1643,29 +1636,12 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
		}
		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
			return -EINVAL;

		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
			*pts = (u64) ((u64)itv->last_dec_timing[2] << 32) |
					(u64)itv->last_dec_timing[1];
			break;
		}
		*pts = 0;
		if (atomic_read(&itv->decoding)) {
			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
				return -EIO;
			}
			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
			*pts = (u64) ((u64) data[2] << 32) | (u64) data[1];
			/*timing->scr = (u64) (((u64) data[4] << 32) | (u64) (data[3]));*/
		}
		break;
		return ivtv_g_pts_frame(itv, pts, &frame);
	}

	case VIDEO_GET_FRAME_COUNT: {
		u32 data[CX2341X_MBOX_MAX_DATA];
		u64 *frame = arg;
		s64 *frame = arg;
		s64 pts;

		IVTV_DEBUG_IOCTL("VIDEO_GET_FRAME_COUNT\n");
		if (s->type < IVTV_DEC_STREAM_TYPE_MPG) {
@@ -1674,22 +1650,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
		}
		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
			return -EINVAL;

		if (test_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags)) {
			*frame = itv->last_dec_timing[0];
			break;
		}
		*frame = 0;
		if (atomic_read(&itv->decoding)) {
			if (ivtv_api(itv, CX2341X_DEC_GET_TIMING_INFO, 5, data)) {
				IVTV_DEBUG_WARN("GET_TIMING: couldn't read clock\n");
				return -EIO;
			}
			memcpy(itv->last_dec_timing, data, sizeof(itv->last_dec_timing));
			set_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
			*frame = data[0];
		}
		break;
		return ivtv_g_pts_frame(itv, &pts, frame);
	}

	case VIDEO_PLAY: {
@@ -1804,17 +1765,13 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
		IVTV_DEBUG_IOCTL("AUDIO_CHANNEL_SELECT\n");
		if (iarg > AUDIO_STEREO_SWAPPED)
			return -EINVAL;
		itv->audio_stereo_mode = iarg;
		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
		return 0;
		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_playback, iarg);

	case AUDIO_BILINGUAL_CHANNEL_SELECT:
		IVTV_DEBUG_IOCTL("AUDIO_BILINGUAL_CHANNEL_SELECT\n");
		if (iarg > AUDIO_STEREO_SWAPPED)
			return -EINVAL;
		itv->audio_bilingual_mode = iarg;
		ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
		return 0;
		return v4l2_ctrl_s_ctrl(itv->ctrl_audio_multilingual_playback, iarg);

	default:
		return -EINVAL;
Loading