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 {