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 <[email protected]>
@@ -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 <[email protected]>
@@ -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 {