Module Name:    src
Committed By:   jmcneill
Date:           Tue Dec 14 03:25:16 UTC 2010

Modified Files:
        src/sys/dev: video.c video_if.h

Log Message:
video(4) changes to support analog tv capture devices:
 - support interlacing with VIDIOC_G_FMT
 - set V4L2_CAP_TUNER if driver implements the set_tuner/get_tuner
   callbacks
 - set V4L2_CAP_AUDIO if driver implements the set_audio/get_audio/enum_audio
   callbacks
 - add support for the following ioctls: VIDIOC_ENUMSTD, VIDIOC_G_STD,
   VIDIOC_S_STD, VIDIOC_ENUMINPUT, VIDIOC_G_INPUT, VIDIOC_S_INPUT,
   VIDIOC_ENUMAUDIO, VIDIOC_G_AUDIO, VIDIOC_S_AUDIO, VIDIOC_G_TUNER,
   VIDIOC_S_TUNER, VIDIOC_G_FREQUENCY, VIDIOC_S_FREQUENCY
 - in video_submit_payload(), fix support for signaling sample complete
   using frame numbers
 - new optional callbacks for drivers: enum_standard, get_standard,
   set_standard, enum_input, get_input, set_input, enum_audio, get_audio,
   set_audio, get_tuner, set_tuner, get_frequency, set_frequency

for drivers that don't provide enum_standard, get_standard, set_standard,
enum_input, get_input and set_input, the original stub implementations are
provided


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/video.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/video_if.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/video.c
diff -u src/sys/dev/video.c:1.23 src/sys/dev/video.c:1.24
--- src/sys/dev/video.c:1.23	Sun Dec  6 22:42:48 2009
+++ src/sys/dev/video.c	Tue Dec 14 03:25:16 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: video.c,v 1.23 2009/12/06 22:42:48 dyoung Exp $ */
+/* $NetBSD: video.c,v 1.24 2010/12/14 03:25:16 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2008 Patrick Mahoney <p...@polycrystal.org>
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: video.c,v 1.23 2009/12/06 22:42:48 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: video.c,v 1.24 2010/12/14 03:25:16 jmcneill Exp $");
 
 #include "video.h"
 #if NVIDEO > 0
@@ -224,8 +224,24 @@
 					    struct video_format *);
 static void	video_format_to_v4l2_format(const struct video_format *,
 					    struct v4l2_format *);
+static void	v4l2_standard_to_video_standard(v4l2_std_id,
+						enum video_standard *);
+static void	video_standard_to_v4l2_standard(enum video_standard,
+						struct v4l2_standard *);
+static void	v4l2_input_to_video_input(const struct v4l2_input *,
+					  struct video_input *);
+static void	video_input_to_v4l2_input(const struct video_input *,
+					  struct v4l2_input *);
+static void	v4l2_audio_to_video_audio(const struct v4l2_audio *,
+					  struct video_audio *);
+static void	video_audio_to_v4l2_audio(const struct video_audio *,
+					  struct v4l2_audio *);
+static void	v4l2_tuner_to_video_tuner(const struct v4l2_tuner *,
+					  struct video_tuner *);
+static void	video_tuner_to_v4l2_tuner(const struct video_tuner *,
+					  struct v4l2_tuner *);
 
-/* V4L2 api functions, typically called from videoioclt() */
+/* V4L2 api functions, typically called from videoioctl() */
 static int	video_enum_format(struct video_softc *, struct v4l2_fmtdesc *);
 static int	video_get_format(struct video_softc *,
 				 struct v4l2_format *);
@@ -233,6 +249,22 @@
 				 struct v4l2_format *);
 static int	video_try_format(struct video_softc *,
 				 struct v4l2_format *);
+static int	video_enum_standard(struct video_softc *,
+				    struct v4l2_standard *);
+static int	video_get_standard(struct video_softc *, v4l2_std_id *);
+static int	video_set_standard(struct video_softc *, v4l2_std_id);
+static int	video_enum_input(struct video_softc *, struct v4l2_input *);
+static int	video_get_input(struct video_softc *, int *);
+static int	video_set_input(struct video_softc *, int);
+static int	video_enum_audio(struct video_softc *, struct v4l2_audio *);
+static int	video_get_audio(struct video_softc *, struct v4l2_audio *);
+static int	video_set_audio(struct video_softc *, struct v4l2_audio *);
+static int	video_get_tuner(struct video_softc *, struct v4l2_tuner *);
+static int	video_set_tuner(struct video_softc *, struct v4l2_tuner *);
+static int	video_get_frequency(struct video_softc *,
+				    struct v4l2_frequency *);
+static int	video_set_frequency(struct video_softc *,
+				    struct v4l2_frequency *);
 static int	video_query_control(struct video_softc *,
 				    struct v4l2_queryctrl *);
 static int	video_get_control(struct video_softc *,
@@ -586,14 +618,25 @@
 	dest->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	dest->fmt.pix.width = src->width;
 	dest->fmt.pix.height = src->height;
-	dest->fmt.pix.field = V4L2_FIELD_NONE; /* TODO: for now,
-						  * just set to
-						  * progressive */
+	if (VIDEO_INTERLACED(src->interlace_flags))
+		dest->fmt.pix.field = V4L2_FIELD_INTERLACED;
+	else
+		dest->fmt.pix.field = V4L2_FIELD_NONE;
 	dest->fmt.pix.bytesperline = src->stride;
 	dest->fmt.pix.sizeimage = src->sample_size;
-	dest->fmt.pix.colorspace = 0;	/* XXX */
 	dest->fmt.pix.priv = src->priv;
 	
+	switch (src->color.primaries) {
+	case VIDEO_COLOR_PRIMARIES_SMPTE_170M:
+		dest->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+		break;
+	/* XXX */
+	case VIDEO_COLOR_PRIMARIES_UNSPECIFIED:
+	default:
+		dest->fmt.pix.colorspace = 0;
+		break;
+	}
+
 	switch (src->pixel_format) {
 	case VIDEO_FORMAT_UYVY:
 		dest->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
@@ -652,6 +695,23 @@
 		dest->stride = src->fmt.pix.bytesperline;
 		dest->sample_size = src->fmt.pix.sizeimage;
 
+		if (src->fmt.pix.field == V4L2_FIELD_INTERLACED)
+			dest->interlace_flags = VIDEO_INTERLACE_ON;
+		else
+			dest->interlace_flags = VIDEO_INTERLACE_OFF;
+
+		switch (src->fmt.pix.colorspace) {
+		case V4L2_COLORSPACE_SMPTE170M:
+			dest->color.primaries =
+			    VIDEO_COLOR_PRIMARIES_SMPTE_170M;
+			break;
+		/* XXX */
+		default:
+			dest->color.primaries =
+			    VIDEO_COLOR_PRIMARIES_UNSPECIFIED;
+			break;
+		}
+
 		switch (src->fmt.pix.pixelformat) {
 		case V4L2_PIX_FMT_UYVY:
 			dest->pixel_format = VIDEO_FORMAT_UYVY;
@@ -720,6 +780,7 @@
 	video_format_to_v4l2_format(&vfmt, &fmt);
 
 	fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* TODO: only one type for now */
+	fmtdesc->flags = 0;
 	if (vfmt.pixel_format >= VIDEO_FORMAT_MJPEG)
 		fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
 	strlcpy(fmtdesc->description,
@@ -798,6 +859,475 @@
 	return 0;
 }
 
+static void
+v4l2_standard_to_video_standard(v4l2_std_id stdid,
+    enum video_standard *vstd)
+{
+#define VSTD(id, vid)	case (id):	*vstd = (vid); break;
+	switch (stdid) {
+	VSTD(V4L2_STD_NTSC_M, VIDEO_STANDARD_NTSC_M)
+	default:
+		*vstd = VIDEO_STANDARD_UNKNOWN;
+		break;
+	}
+#undef VSTD
+}
+
+static void
+video_standard_to_v4l2_standard(enum video_standard vstd,
+    struct v4l2_standard *std)
+{
+	switch (vstd) {
+	case VIDEO_STANDARD_NTSC_M:
+		std->id = V4L2_STD_NTSC_M;
+		strlcpy(std->name, "NTSC-M", sizeof(std->name));
+		std->frameperiod.numerator = 1001;
+		std->frameperiod.denominator = 30000;
+		std->framelines = 525;
+		break;
+	default:
+		std->id = V4L2_STD_UNKNOWN;
+		strlcpy(std->name, "Unknown", sizeof(std->name));
+		break;
+	}
+}
+
+static int
+video_enum_standard(struct video_softc *sc, struct v4l2_standard *std)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	enum video_standard vstd;
+	int err;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->enum_standard == NULL) {
+		if (std->index != 0)
+			return EINVAL;
+		std->id = V4L2_STD_UNKNOWN;
+		strlcpy(std->name, "webcam", sizeof(std->name));
+		return 0;
+	}
+
+	v4l2_standard_to_video_standard(std->id, &vstd);
+
+	err = hw->enum_standard(sc->hw_softc, std->index, &vstd);
+	if (err != 0)
+		return err;
+
+	video_standard_to_v4l2_standard(vstd, std);
+
+	return 0;
+}
+
+static int
+video_get_standard(struct video_softc *sc, v4l2_std_id *stdid)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct v4l2_standard std;
+	enum video_standard vstd;
+	int err;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->get_standard == NULL) {
+		*stdid = V4L2_STD_UNKNOWN;
+		return 0;
+	}
+
+	err = hw->get_standard(sc->hw_softc, &vstd);
+	if (err != 0)
+		return err;
+
+	video_standard_to_v4l2_standard(vstd, &std);
+	*stdid = std.id;
+	
+	return 0;
+}
+
+static int
+video_set_standard(struct video_softc *sc, v4l2_std_id stdid)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	enum video_standard vstd;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->set_standard == NULL) {
+		if (stdid != V4L2_STD_UNKNOWN)
+			return EINVAL;
+		return 0;
+	}
+
+	v4l2_standard_to_video_standard(stdid, &vstd);
+
+	return hw->set_standard(sc->hw_softc, vstd);
+}
+
+static void
+v4l2_input_to_video_input(const struct v4l2_input *input,
+    struct video_input *vi)
+{
+	vi->index = input->index;
+	strlcpy(vi->name, input->name, sizeof(vi->name));
+	switch (input->type) {
+	case V4L2_INPUT_TYPE_TUNER:
+		vi->type = VIDEO_INPUT_TYPE_TUNER;
+		break;
+	case V4L2_INPUT_TYPE_CAMERA:
+		vi->type = VIDEO_INPUT_TYPE_CAMERA;
+		break;
+	}
+	vi->audiomask = input->audioset;
+	vi->tuner_index = input->tuner;
+	vi->standards = input->std;	/* ... values are the same */
+	vi->status = 0;
+	if (input->status & V4L2_IN_ST_NO_POWER)
+		vi->status |= VIDEO_STATUS_NO_POWER;
+	if (input->status & V4L2_IN_ST_NO_SIGNAL)
+		vi->status |= VIDEO_STATUS_NO_SIGNAL;
+	if (input->status & V4L2_IN_ST_NO_COLOR)
+		vi->status |= VIDEO_STATUS_NO_COLOR;
+	if (input->status & V4L2_IN_ST_NO_H_LOCK)
+		vi->status |= VIDEO_STATUS_NO_HLOCK;
+	if (input->status & V4L2_IN_ST_MACROVISION)
+		vi->status |= VIDEO_STATUS_MACROVISION;
+}
+
+static void
+video_input_to_v4l2_input(const struct video_input *vi,
+    struct v4l2_input *input)
+{
+	input->index = vi->index;
+	strlcpy(input->name, vi->name, sizeof(input->name));
+	switch (vi->type) {
+	case VIDEO_INPUT_TYPE_TUNER:
+		input->type = V4L2_INPUT_TYPE_TUNER;
+		break;
+	case VIDEO_INPUT_TYPE_CAMERA:
+		input->type = V4L2_INPUT_TYPE_CAMERA;
+		break;
+	}
+	input->audioset = vi->audiomask;
+	input->tuner = vi->tuner_index;
+	input->std = vi->standards;	/* ... values are the same */
+	input->status = 0;
+	if (vi->status & VIDEO_STATUS_NO_POWER)
+		input->status |= V4L2_IN_ST_NO_POWER;
+	if (vi->status & VIDEO_STATUS_NO_SIGNAL)
+		input->status |= V4L2_IN_ST_NO_SIGNAL;
+	if (vi->status & VIDEO_STATUS_NO_COLOR)
+		input->status |= V4L2_IN_ST_NO_COLOR;
+	if (vi->status & VIDEO_STATUS_NO_HLOCK)
+		input->status |= V4L2_IN_ST_NO_H_LOCK;
+	if (vi->status & VIDEO_STATUS_MACROVISION)
+		input->status |= V4L2_IN_ST_MACROVISION;
+}
+
+static int
+video_enum_input(struct video_softc *sc, struct v4l2_input *input)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_input vi;
+	int err;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->enum_input == NULL) {
+		if (input->index != 0)
+			return EINVAL;
+		memset(input, 0, sizeof(*input));
+		input->index = 0;
+		strlcpy(input->name, "Camera", sizeof(input->name));
+		input->type = V4L2_INPUT_TYPE_CAMERA;
+		return 0;
+	}
+
+	v4l2_input_to_video_input(input, &vi);
+
+	err = hw->enum_input(sc->hw_softc, input->index, &vi);
+	if (err != 0)
+		return err;
+
+	video_input_to_v4l2_input(&vi, input);
+
+	return 0;
+}
+
+static int
+video_get_input(struct video_softc *sc, int *index)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_input vi;
+	struct v4l2_input input;
+	int err;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->get_input == NULL) {
+		*index = 0;
+		return 0;
+	}
+
+	input.index = *index;
+	v4l2_input_to_video_input(&input, &vi);
+
+	err = hw->get_input(sc->hw_softc, &vi);
+	if (err != 0)
+		return err;
+
+	video_input_to_v4l2_input(&vi, &input);
+	*index = input.index;
+
+	return 0;
+}
+
+static int
+video_set_input(struct video_softc *sc, int index)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_input vi;
+	struct v4l2_input input;
+
+	/* simple webcam drivers don't need to implement this callback */
+	if (hw->set_input == NULL) {
+		if (index != 0)
+			return EINVAL;
+		return 0;
+	}
+
+	input.index = index;
+	v4l2_input_to_video_input(&input, &vi);
+
+	return hw->set_input(sc->hw_softc, &vi);
+}
+
+static void
+v4l2_audio_to_video_audio(const struct v4l2_audio *audio,
+    struct video_audio *va)
+{
+	va->index = audio->index;
+	strlcpy(va->name, audio->name, sizeof(va->name));
+	va->caps = va->mode = 0;
+	if (audio->capability & V4L2_AUDCAP_STEREO)
+		va->caps |= VIDEO_AUDIO_F_STEREO;
+	if (audio->capability & V4L2_AUDCAP_AVL)
+		va->caps |= VIDEO_AUDIO_F_AVL;
+	if (audio->mode & V4L2_AUDMODE_AVL)
+		va->mode |= VIDEO_AUDIO_F_AVL;
+}
+
+static void
+video_audio_to_v4l2_audio(const struct video_audio *va,
+    struct v4l2_audio *audio)
+{
+	audio->index = va->index;
+	strlcpy(audio->name, va->name, sizeof(audio->name));
+	audio->capability = audio->mode = 0;
+	if (va->caps & VIDEO_AUDIO_F_STEREO)
+		audio->capability |= V4L2_AUDCAP_STEREO;
+	if (va->caps & VIDEO_AUDIO_F_AVL)
+		audio->capability |= V4L2_AUDCAP_AVL;
+	if (va->mode & VIDEO_AUDIO_F_AVL)
+		audio->mode |= V4L2_AUDMODE_AVL;
+}
+
+static int
+video_enum_audio(struct video_softc *sc, struct v4l2_audio *audio)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_audio va;
+	int err;
+
+	if (hw->enum_audio == NULL)
+		return ENOTTY;
+
+	v4l2_audio_to_video_audio(audio, &va);
+
+	err = hw->enum_audio(sc->hw_softc, audio->index, &va);
+	if (err != 0)
+		return err;
+
+	video_audio_to_v4l2_audio(&va, audio);
+
+	return 0;
+}
+
+static int
+video_get_audio(struct video_softc *sc, struct v4l2_audio *audio)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_audio va;
+	int err;
+
+	if (hw->get_audio == NULL)
+		return ENOTTY;
+
+	v4l2_audio_to_video_audio(audio, &va);
+
+	err = hw->get_audio(sc->hw_softc, &va);
+	if (err != 0)
+		return err;
+
+	video_audio_to_v4l2_audio(&va, audio);
+
+	return 0;
+}
+
+static int
+video_set_audio(struct video_softc *sc, struct v4l2_audio *audio)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_audio va;
+
+	if (hw->set_audio == NULL)
+		return ENOTTY;
+
+	v4l2_audio_to_video_audio(audio, &va);
+
+	return hw->set_audio(sc->hw_softc, &va);
+}
+
+static void
+v4l2_tuner_to_video_tuner(const struct v4l2_tuner *tuner,
+    struct video_tuner *vt)
+{
+	vt->index = tuner->index;
+	strlcpy(vt->name, tuner->name, sizeof(vt->name));
+	vt->freq_lo = tuner->rangelow;
+	vt->freq_hi = tuner->rangehigh;
+	vt->signal = tuner->signal;
+	vt->afc = tuner->afc;
+	vt->caps = 0;
+	if (tuner->capability & V4L2_TUNER_CAP_STEREO)
+		vt->caps |= VIDEO_TUNER_F_STEREO;
+	if (tuner->capability & V4L2_TUNER_CAP_LANG1)
+		vt->caps |= VIDEO_TUNER_F_LANG1;
+	if (tuner->capability & V4L2_TUNER_CAP_LANG2)
+		vt->caps |= VIDEO_TUNER_F_LANG2;
+	switch (tuner->audmode) {
+	case V4L2_TUNER_MODE_MONO:
+		vt->mode = VIDEO_TUNER_F_MONO;
+		break;
+	case V4L2_TUNER_MODE_STEREO:
+		vt->mode = VIDEO_TUNER_F_STEREO;
+		break;
+	case V4L2_TUNER_MODE_LANG1:
+		vt->mode = VIDEO_TUNER_F_LANG1;
+		break;
+	case V4L2_TUNER_MODE_LANG2:
+		vt->mode = VIDEO_TUNER_F_LANG2;
+		break;
+	case V4L2_TUNER_MODE_LANG1_LANG2:
+		vt->mode = VIDEO_TUNER_F_LANG1 | VIDEO_TUNER_F_LANG2;
+		break;
+	}
+}
+
+static void
+video_tuner_to_v4l2_tuner(const struct video_tuner *vt,
+    struct v4l2_tuner *tuner)
+{
+	tuner->index = vt->index;
+	strlcpy(tuner->name, vt->name, sizeof(tuner->name));
+	tuner->rangelow = vt->freq_lo;
+	tuner->rangehigh = vt->freq_hi;
+	tuner->signal = vt->signal;
+	tuner->afc = vt->afc;
+	tuner->capability = 0;
+	if (vt->caps & VIDEO_TUNER_F_STEREO)
+		tuner->capability |= V4L2_TUNER_CAP_STEREO;
+	if (vt->caps & VIDEO_TUNER_F_LANG1)
+		tuner->capability |= V4L2_TUNER_CAP_LANG1;
+	if (vt->caps & VIDEO_TUNER_F_LANG2)
+		tuner->capability |= V4L2_TUNER_CAP_LANG2;
+	switch (vt->mode) {
+	case VIDEO_TUNER_F_MONO:
+		tuner->audmode = V4L2_TUNER_MODE_MONO;
+		break;
+	case VIDEO_TUNER_F_STEREO:
+		tuner->audmode = V4L2_TUNER_MODE_STEREO;
+		break;
+	case VIDEO_TUNER_F_LANG1:
+		tuner->audmode = V4L2_TUNER_MODE_LANG1;
+		break;
+	case VIDEO_TUNER_F_LANG2:
+		tuner->audmode = V4L2_TUNER_MODE_LANG2;
+		break;
+	case VIDEO_TUNER_F_LANG1|VIDEO_TUNER_F_LANG2:
+		tuner->audmode = V4L2_TUNER_MODE_LANG1_LANG2;
+		break;
+	}
+}
+
+static int
+video_get_tuner(struct video_softc *sc, struct v4l2_tuner *tuner)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_tuner vt;
+	int err;
+
+	if (hw->get_tuner == NULL)
+		return ENOTTY;
+
+	v4l2_tuner_to_video_tuner(tuner, &vt);
+
+	err = hw->get_tuner(sc->hw_softc, &vt);
+	if (err != 0)
+		return err;
+
+	video_tuner_to_v4l2_tuner(&vt, tuner);
+
+	return 0;
+}
+
+static int
+video_set_tuner(struct video_softc *sc, struct v4l2_tuner *tuner)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_tuner vt;
+
+	if (hw->set_tuner == NULL)
+		return ENOTTY;
+
+	v4l2_tuner_to_video_tuner(tuner, &vt);
+
+	return hw->set_tuner(sc->hw_softc, &vt);
+}
+
+static int
+video_get_frequency(struct video_softc *sc, struct v4l2_frequency *freq)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_frequency vfreq;
+	int err;
+
+	if (hw->get_frequency == NULL)
+		return ENOTTY;
+
+	err = hw->get_frequency(sc->hw_softc, &vfreq);
+	if (err)
+		return err;
+
+	freq->tuner = vfreq.tuner_index;
+	freq->type = V4L2_TUNER_ANALOG_TV;
+	freq->frequency = vfreq.frequency;
+
+	return 0;
+}
+
+static int
+video_set_frequency(struct video_softc *sc, struct v4l2_frequency *freq)
+{
+	const struct video_hw_if *hw = sc->hw_if;
+	struct video_frequency vfreq;
+
+	if (hw->set_frequency == NULL)
+		return ENOTTY;
+	if (freq->type != V4L2_TUNER_ANALOG_TV)
+		return EINVAL;
+
+	vfreq.tuner_index = freq->tuner;
+	vfreq.frequency = freq->frequency;
+
+	return hw->set_frequency(sc->hw_softc, &vfreq);
+}
+
 /* Takes a single Video4Linux2 control, converts it to a struct
  * video_control, and calls the hardware driver. */
 static int
@@ -1290,6 +1820,9 @@
 	struct v4l2_format *fmt;
 	struct v4l2_standard *std;
 	struct v4l2_input *input;
+	struct v4l2_audio *audio;
+	struct v4l2_tuner *tuner;
+	struct v4l2_frequency *freq;
 	struct v4l2_control *control;
 	struct v4l2_queryctrl *query;
 	struct v4l2_requestbuffers *reqbufs;
@@ -1322,6 +1855,11 @@
 		if (hw->start_transfer != NULL && hw->stop_transfer != NULL)
 			cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE |
 			    V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+		if (hw->set_tuner != NULL && hw->get_tuner != NULL)
+			cap->capabilities |= V4L2_CAP_TUNER;
+		if (hw->set_audio != NULL && hw->get_audio != NULL &&
+		    hw->enum_audio != NULL)
+			cap->capabilities |= V4L2_CAP_AUDIO;
 		return 0;
 	case VIDIOC_ENUM_FMT:
 		/* TODO: for now, just enumerate one default format */
@@ -1331,7 +1869,7 @@
 		return video_enum_format(sc, fmtdesc);
 	case VIDIOC_G_FMT:
 		fmt = data;
-		return (video_get_format(sc, fmt));
+		return video_get_format(sc, fmt);
 	case VIDIOC_S_FMT:
 		fmt = data;
 		if ((flag & FWRITE) == 0)
@@ -1339,47 +1877,56 @@
 		return video_set_format(sc, fmt);
 	case VIDIOC_TRY_FMT:
 		fmt = data;
-		return (video_try_format(sc, fmt));
+		return video_try_format(sc, fmt);
 	case VIDIOC_ENUMSTD:
-		/* TODO: implement properly */
 		std = data;
-		if (std->index != 0)
-			return EINVAL;
-		std->id = V4L2_STD_UNKNOWN;
-		strlcpy(std->name, "webcam", sizeof(std->name));
-		return 0;
+		return video_enum_standard(sc, std);
 	case VIDIOC_G_STD:
-		/* TODO: implement properly */
 		stdid = data;
-		*stdid = V4L2_STD_UNKNOWN;
-		return 0;
+		return video_get_standard(sc, stdid);
 	case VIDIOC_S_STD:
-		/* TODO: implement properly */
 		stdid = data;
-		if (*stdid != V4L2_STD_UNKNOWN)
-			return EINVAL;
-		return 0;
+		if ((flag & FWRITE) == 0)
+			return EPERM;
+		return video_set_standard(sc, *stdid);
 	case VIDIOC_ENUMINPUT:
-		/* TODO: implement properly */
 		input = data;
-		if (input->index != 0)
-			return EINVAL;
-		memset(input, 0, sizeof(*input));
-		input->index = 0;
-		strlcpy(input->name, "Camera", sizeof(input->name));
-		input->type = V4L2_INPUT_TYPE_CAMERA;
-		return 0;
+		return video_enum_input(sc, input);
 	case VIDIOC_G_INPUT:
-		/* TODO: implement properly */
 		ip = data;
-		*ip = 0;
-		return 0;
+		return video_get_input(sc, ip);
 	case VIDIOC_S_INPUT:
-		/* TODO: implement properly */
 		ip = data;
-		if (*ip != 0)
-			return EINVAL;
-		return 0;
+		if ((flag & FWRITE) == 0)
+			return EPERM;
+		return video_set_input(sc, *ip);
+	case VIDIOC_ENUMAUDIO:
+		audio = data;
+		return video_enum_audio(sc, audio);
+	case VIDIOC_G_AUDIO:
+		audio = data;
+		return video_get_audio(sc, audio);
+	case VIDIOC_S_AUDIO:
+		audio = data;
+		if ((flag & FWRITE) == 0)
+			return EPERM;
+		return video_set_audio(sc, audio);
+	case VIDIOC_G_TUNER:
+		tuner = data;
+		return video_get_tuner(sc, tuner);
+	case VIDIOC_S_TUNER:
+		tuner = data;
+		if ((flag & FWRITE) == 0)
+			return EPERM;
+		return video_set_tuner(sc, tuner);
+	case VIDIOC_G_FREQUENCY:
+		freq = data;
+		return video_get_frequency(sc, freq);
+	case VIDIOC_S_FREQUENCY:
+		freq = data;
+		if ((flag & FWRITE) == 0)
+			return EPERM;
+		return video_set_frequency(sc, freq);
 	case VIDIOC_QUERYCTRL:
 		query = data;
 		return (video_query_control(sc, query));
@@ -1937,8 +2484,10 @@
 	mutex_enter(&vs->vs_lock);
 
 	/* change of frameno implies end of current frame */
-	if (vs->vs_frameno > 0 && vs->vs_frameno != payload->frameno)
+	if (vs->vs_frameno >= 0 && vs->vs_frameno != payload->frameno)
 		video_stream_sample_done(vs);
+
+	vs->vs_frameno = payload->frameno;
 	
 	if (vs->vs_drop || SIMPLEQ_EMPTY(&vs->vs_ingress)) {
 		/* DPRINTF(("video_stream_write: dropping sample %d\n",

Index: src/sys/dev/video_if.h
diff -u src/sys/dev/video_if.h:1.5 src/sys/dev/video_if.h:1.6
--- src/sys/dev/video_if.h:1.5	Sat Sep 20 18:13:40 2008
+++ src/sys/dev/video_if.h	Tue Dec 14 03:25:16 2010
@@ -1,4 +1,4 @@
-/* $NetBSD: video_if.h,v 1.5 2008/09/20 18:13:40 jmcneill Exp $ */
+/* $NetBSD: video_if.h,v 1.6 2010/12/14 03:25:16 jmcneill Exp $ */
 
 /*
  * Copyright (c) 2008 Patrick Mahoney <p...@polycrystal.org>
@@ -199,6 +199,35 @@
 	VIDEO_FORMAT_MPEG
 };
 
+/* video standards */
+enum video_standard {
+	VIDEO_STANDARD_PAL_B		= 0x00000001,
+	VIDEO_STANDARD_PAL_B1		= 0x00000002,
+	VIDEO_STANDARD_PAL_G		= 0x00000004,
+	VIDEO_STANDARD_PAL_H		= 0x00000008,
+	VIDEO_STANDARD_PAL_I		= 0x00000010,
+	VIDEO_STANDARD_PAL_D		= 0x00000020,
+	VIDEO_STANDARD_PAL_D1		= 0x00000040,
+	VIDEO_STANDARD_PAL_K		= 0x00000080,
+	VIDEO_STANDARD_PAL_M		= 0x00000100,
+	VIDEO_STANDARD_PAL_N		= 0x00000200,
+	VIDEO_STANDARD_PAL_Nc		= 0x00000400,
+	VIDEO_STANDARD_PAL_60		= 0x00000800,
+	VIDEO_STANDARD_NTSC_M		= 0x00001000,
+	VIDEO_STANDARD_NTSC_M_JP	= 0x00002000,
+	VIDEO_STANDARD_NTSC_443		= 0x00004000,
+	VIDEO_STANDARD_NTSC_M_KR	= 0x00008000,
+	VIDEO_STANDARD_SECAM_B		= 0x00010000,
+	VIDEO_STANDARD_SECAM_D		= 0x00020000,
+	VIDEO_STANDARD_SECAM_G		= 0x00040000,
+	VIDEO_STANDARD_SECAM_H		= 0x00080000,
+	VIDEO_STANDARD_SECAM_K		= 0x00100000,
+	VIDEO_STANDARD_SECAM_K1		= 0x00200000,
+	VIDEO_STANDARD_SECAM_L		= 0x00400000,
+
+	VIDEO_STANDARD_UNKNOWN		= 0x00000000
+};
+
 /* interlace_flags bits are allocated like this:
       7 6 5 4 3 2 1 0
 	    \_/ | | |interlaced or progressive
@@ -360,6 +389,66 @@
 					 * payload in the frame. */
 };
 
+/* tuner frequency, frequencies are in units of 62.5 kHz */
+struct video_frequency {
+	uint32_t	tuner_index;
+	uint32_t	frequency;
+};
+
+/* video tuner capability flags */
+#define	VIDEO_TUNER_F_MONO	(1 << 0)
+#define	VIDEO_TUNER_F_STEREO	(1 << 1)
+#define	VIDEO_TUNER_F_LANG1	(1 << 2)
+#define	VIDEO_TUNER_F_LANG2	(1 << 3)
+
+/* Video tuner definition */
+struct video_tuner {
+	uint32_t	index;
+	char		name[32];	/* tuner name */
+	uint32_t	freq_lo;	/* lowest tunable frequency */
+	uint32_t	freq_hi;	/* highest tunable frequency */
+	uint32_t	caps;		/* capability flags */
+	uint32_t	mode;		/* audio mode flags */
+	uint32_t	signal;		/* signal strength */
+	int32_t		afc;		/* automatic frequency control */
+};
+
+/* Video input capability flags */
+enum video_input_type {
+	VIDEO_INPUT_TYPE_TUNER,		/* RF demodulator */
+	VIDEO_INPUT_TYPE_BASEBAND,	/* analog baseband */
+	VIDEO_INPUT_TYPE_CAMERA = VIDEO_INPUT_TYPE_BASEBAND,
+};
+
+#define VIDEO_STATUS_NO_POWER		(1 << 0)
+#define	VIDEO_STATUS_NO_SIGNAL		(1 << 1)
+#define	VIDEO_STATUS_NO_COLOR		(1 << 2)
+#define	VIDEO_STATUS_NO_HLOCK		(1 << 3)
+#define	VIDEO_STATUS_MACROVISION	(1 << 4)
+
+/* Video input definition */
+struct video_input {
+	uint32_t	index;
+	char		name[32];	/* video input name */
+	enum video_input_type type;	/* input type */
+	uint32_t	audiomask;	/* bitmask of assoc. audio inputs */
+	uint32_t	tuner_index;	/* tuner index if applicable */
+	uint64_t	standards;	/* all supported standards */
+	uint32_t	status;		/* input status */
+};
+
+/* Audio input capability flags */
+#define	VIDEO_AUDIO_F_STEREO	(1 << 0)
+#define	VIDEO_AUDIO_F_AVL	(1 << 1)
+
+/* Audio input definition */
+struct video_audio {
+	uint32_t	index;
+	char		name[32];	/* audio input name */
+	uint32_t	caps;		/* capabilities flags */
+	uint32_t	mode;		/* audio mode flags */
+};
+
 struct video_hw_if {
 	int	(*open)(void *, int); /* open hardware */
 	void	(*close)(void *);     /* close hardware */
@@ -371,6 +460,10 @@
 	int	(*set_format)(void *, struct video_format *);
 	int	(*try_format)(void *, struct video_format *);
 
+	int	(*enum_standard)(void *, uint32_t, enum video_standard *);
+	int	(*get_standard)(void *, enum video_standard *);
+	int	(*set_standard)(void *, enum video_standard);
+
 	int	(*start_transfer)(void *);
 	int	(*stop_transfer)(void *);
 
@@ -380,6 +473,20 @@
 					  struct video_control_desc_group *);
 	int	(*get_control_group)(void *, struct video_control_group *);
 	int	(*set_control_group)(void *, const struct video_control_group *);
+
+	int	(*enum_input)(void *, uint32_t, struct video_input *);
+	int	(*get_input)(void *, struct video_input *);
+	int	(*set_input)(void *, struct video_input *);
+
+	int	(*enum_audio)(void *, uint32_t, struct video_audio *);
+	int	(*get_audio)(void *, struct video_audio *);
+	int	(*set_audio)(void *, struct video_audio *);
+
+	int	(*get_tuner)(void *, struct video_tuner *);
+	int	(*set_tuner)(void *, struct video_tuner *);
+
+	int	(*get_frequency)(void *, struct video_frequency *);
+	int	(*set_frequency)(void *, struct video_frequency *);
 };
 
 struct video_attach_args {

Reply via email to