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
This commit is contained in:
jmcneill 2010-12-14 03:25:16 +00:00
parent 89d498aa24
commit c618ceecc4
2 changed files with 695 additions and 39 deletions

View File

@ -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 <pat@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 @@ static void v4l2_format_to_video_format(const struct v4l2_format *,
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 @@ static int video_set_format(struct video_softc *,
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 @@ video_format_to_v4l2_format(const struct video_format *src,
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 @@ v4l2_format_to_video_format(const struct v4l2_format *src,
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_enum_format(struct video_softc *sc, struct v4l2_fmtdesc *fmtdesc)
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 @@ video_try_format(struct video_softc *sc,
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 @@ videoioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
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 @@ videoioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
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 @@ videoioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
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 @@ videoioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
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,9 +2484,11 @@ video_stream_write(struct video_stream *vs,
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",
vs->vs_sequence)); */

View File

@ -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 <pat@polycrystal.org>
@ -199,6 +199,35 @@ enum video_pixel_format {
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 @@ struct video_payload {
* 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 @@ struct video_hw_if {
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_hw_if {
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 {