Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F164184570
D58369.id182736.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D58369.id182736.diff
View Options
diff --git a/share/man/man4/fwcam.4 b/share/man/man4/fwcam.4
--- a/share/man/man4/fwcam.4
+++ b/share/man/man4/fwcam.4
@@ -31,12 +31,13 @@
This avoids bus resets on controllers where early register access
destabilizes the link.
.Pp
-Video frames are received over an isochronous DMA channel and exposed
-through a character device.
-Applications read raw frames from
-.Pa /dev/fwcamX
-and configure the camera via
-.Xr ioctl 2 .
+Video frames are received over an isochronous DMA channel and delivered
+through the
+.Xr video 4
+framework.
+Applications access the camera via
+.Pa /dev/videoN
+using the V4L2 interface.
.Pp
The driver supports Format_0 (VGA non-compressed) video with the
following modes:
@@ -109,14 +110,16 @@
.Xr loader.conf 5 .
.El
.Sh FILES
-.Bl -tag -width "/dev/fwcamX" -compact
-.It Pa /dev/fwcamX
-Camera character device.
-Read to obtain raw video frames.
+.Bl -tag -width "/dev/videoN" -compact
+.It Pa /dev/videoN
+Video capture device provided by the
+.Xr video 4
+framework.
.El
.Sh SEE ALSO
.Xr firewire 4 ,
-.Xr fwohci 4
+.Xr fwohci 4 ,
+.Xr video 4
.Pp
IIDC 1394-based Digital Camera Specification v1.30,
1394 Trade Association Document 1999023.
diff --git a/share/man/man4/video.4 b/share/man/man4/video.4
--- a/share/man/man4/video.4
+++ b/share/man/man4/video.4
@@ -74,9 +74,23 @@
Up to 8 buffers may be allocated per device.
Buffer memory remains valid until the last mapping is unmapped,
even if the device is closed or detached.
+.Sh HARDWARE
+The following drivers use the
+.Nm
+framework:
+.Bl -bullet -compact
+.It
+.Xr uvideo 4
+\(em USB Video Class devices
+.It
+.Xr fwcam 4
+\(em IIDC/DCAM FireWire cameras
+.El
.Sh SEE ALSO
.Xr mmap 2 ,
-.Xr read 2
+.Xr read 2 ,
+.Xr fwcam 4 ,
+.Xr uvideo 4
.Sh HISTORY
The
.Nm
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1732,7 +1732,7 @@
dev/firewire/firewire.c optional firewire
dev/firewire/fwcrom.c optional firewire
dev/firewire/fwdev.c optional firewire
-dev/firewire/fwcam.c optional fwcam
+dev/firewire/fwcam.c optional fwcam video
dev/firewire/fwdma.c optional firewire
dev/firewire/fwdv.c optional fwdv
dev/firewire/fwisound.c optional fwisound sound
diff --git a/sys/dev/firewire/fwcam.h b/sys/dev/firewire/fwcam.h
--- a/sys/dev/firewire/fwcam.h
+++ b/sys/dev/firewire/fwcam.h
@@ -281,10 +281,16 @@
#define FWCAM_ISO_PKTSIZE 2048 /* max iso packet size (MCLBYTES) */
#ifdef _KERNEL
+
+struct video_device;
+
struct fwcam_softc {
struct firewire_dev_comm fd; /* must be first */
struct mtx mtx;
- struct cdev *cdev;
+
+ /* video(4) framework handle */
+ struct video_device *sc_vd;
+ uint32_t sc_sequence;
/* Remote camera node */
struct fw_device *fwdev;
@@ -315,16 +321,11 @@
int dma_ch; /* IR DMA channel, -1 if none */
int iso_active; /* iso_input running */
- /* Frame assembly (double buffer) */
+ /* Frame assembly */
uint8_t *frame_buf; /* frame being assembled */
- uint8_t *read_buf; /* completed frame for read() */
uint32_t frame_size; /* expected frame size (bytes) */
uint32_t frame_offset; /* write position in frame_buf */
- int frame_ready; /* read_buf has valid frame */
- int read_in_progress; /* uiomove active on read_buf */
int frame_dropped; /* dropped frame count */
- int open_count; /* cdev open count */
- struct selinfo rsel; /* poll/select/kqueue */
/* State: one of FWCAM_STATE_* */
int state;
diff --git a/sys/dev/firewire/fwcam.c b/sys/dev/firewire/fwcam.c
--- a/sys/dev/firewire/fwcam.c
+++ b/sys/dev/firewire/fwcam.c
@@ -9,6 +9,7 @@
*
* Implements the IIDC v1.30 specification (TA Document 1999023) for
* FireWire digital cameras.
+ *
*/
#include <sys/param.h>
@@ -16,16 +17,11 @@
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/kernel.h>
-#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sysctl.h>
#include <sys/taskqueue.h>
-#include <sys/fcntl.h>
-#include <sys/poll.h>
-#include <sys/selinfo.h>
-#include <sys/uio.h>
#include <sys/mbuf.h>
#include <dev/firewire/firewire.h>
@@ -34,6 +30,9 @@
#include <dev/firewire/fwcam.h>
#include <dev/firewire/fw_helpers.h>
+#include <dev/usb/video/uvideo_v4l2.h>
+#include <dev/video/video_if.h>
+
static MALLOC_DEFINE(M_FWCAM, "fwcam", "IIDC FireWire Camera");
static int debug = 0;
@@ -59,24 +58,72 @@
static int fwcam_iso_start(struct fwcam_softc *);
static void fwcam_iso_stop(struct fwcam_softc *);
static void fwcam_iso_input(struct fw_xferq *);
+static void fwcam_frame_done(struct fwcam_softc *);
+
+static int fwcam_hw_open(void *);
+static int fwcam_hw_querycap(void *, struct video_caps *);
+static int fwcam_hw_enum_format(void *, uint32_t, struct video_format *);
+static int fwcam_hw_get_format(void *, struct video_format *);
+static int fwcam_hw_try_format(void *, struct video_format *);
+static int fwcam_hw_set_format(void *, const struct video_format *);
+static int fwcam_hw_enum_framesizes(void *, struct video_frmsizeenum *);
+static int fwcam_hw_enum_input(void *, uint32_t, struct video_input *);
+static int fwcam_hw_get_input(void *, uint32_t *);
+static int fwcam_hw_set_input(void *, uint32_t);
+static int fwcam_hw_query_control(void *, struct video_control_desc *);
+static int fwcam_hw_get_control(void *, struct video_control *);
+static int fwcam_hw_set_control(void *, const struct video_control *);
+static int fwcam_hw_start_stream(void *);
+static void fwcam_hw_stop_stream(void *);
+
+static const struct video_hw_ops fwcam_hw_ops = {
+ .open = fwcam_hw_open,
+ .querycap = fwcam_hw_querycap,
+ .enum_format = fwcam_hw_enum_format,
+ .get_format = fwcam_hw_get_format,
+ .try_format = fwcam_hw_try_format,
+ .set_format = fwcam_hw_set_format,
+ .enum_framesizes = fwcam_hw_enum_framesizes,
+ .enum_input = fwcam_hw_enum_input,
+ .get_input = fwcam_hw_get_input,
+ .set_input = fwcam_hw_set_input,
+ .query_control = fwcam_hw_query_control,
+ .get_control = fwcam_hw_get_control,
+ .set_control = fwcam_hw_set_control,
+ .start_stream = fwcam_hw_start_stream,
+ .stop_stream = fwcam_hw_stop_stream,
+};
-static d_open_t fwcam_cdev_open;
-static d_close_t fwcam_cdev_close;
-static d_read_t fwcam_cdev_read;
-static d_poll_t fwcam_cdev_poll;
-static d_ioctl_t fwcam_cdev_ioctl;
-
-static struct cdevsw fwcam_cdevsw = {
- .d_version = D_VERSION,
- .d_flags = D_TRACKCLOSE,
- .d_open = fwcam_cdev_open,
- .d_close = fwcam_cdev_close,
- .d_read = fwcam_cdev_read,
- .d_poll = fwcam_cdev_poll,
- .d_ioctl = fwcam_cdev_ioctl,
- .d_name = "fwcam",
+/*
+ * Format_0 (VGA) mode descriptors for V4L2 mapping.
+ */
+struct fwcam_v4l2_mode {
+ uint32_t pixelformat; /* V4L2 fourcc */
+ uint32_t width;
+ uint32_t height;
+ uint32_t bytesperline;
+ uint32_t sizeimage;
};
+static const struct fwcam_v4l2_mode fwcam_fmt0_v4l2[] = {
+ /* mode 0: 160x120 YUV444 (24bpp packed) */
+ { V4L2_PIX_FMT_YUV444, 160, 120, 160 * 3, 160 * 120 * 3 },
+ /* mode 1: 320x240 YUV422 (UYVY, 16bpp packed) */
+ { V4L2_PIX_FMT_UYVY, 320, 240, 320 * 2, 320 * 240 * 2 },
+ /* mode 2: 640x480 YUV411 (12bpp) */
+ { V4L2_PIX_FMT_Y41P, 640, 480, 640 * 3 / 2, 640 * 480 * 3 / 2 },
+ /* mode 3: 640x480 YUV422 (UYVY, 16bpp packed) */
+ { V4L2_PIX_FMT_UYVY, 640, 480, 640 * 2, 640 * 480 * 2 },
+ /* mode 4: 640x480 RGB8 (24bpp) */
+ { V4L2_PIX_FMT_RGB24, 640, 480, 640 * 3, 640 * 480 * 3 },
+ /* mode 5: 640x480 Mono8 */
+ { V4L2_PIX_FMT_GREY, 640, 480, 640, 640 * 480 },
+ /* mode 6: 640x480 Mono16 */
+ { V4L2_PIX_FMT_Y16, 640, 480, 640 * 2, 640 * 480 * 2 },
+};
+
+#define FWCAM_FMT0_V4L2_NMODES nitems(fwcam_fmt0_v4l2)
+
/*
* Search a CSR directory for the IIDC command base register (key 0x40).
* The iSight places cmd_base inside a logical_unit_directory nested
@@ -347,17 +394,10 @@
static uint32_t
fwcam_frame_size(struct fwcam_softc *sc)
{
- static const uint32_t fmt0_sizes[] = {
- 160 * 120 * 3, /* mode 0: YUV444 */
- 320 * 240 * 2, /* mode 1: YUV422 */
- 640 * 480 * 3 / 2, /* mode 2: YUV411 */
- 640 * 480 * 2, /* mode 3: YUV422 */
- 640 * 480 * 3, /* mode 4: RGB8 */
- 640 * 480, /* mode 5: Mono8 */
- };
-
- if (sc->cur_format == IIDC_FMT_VGA && sc->cur_mode < nitems(fmt0_sizes))
- return (fmt0_sizes[sc->cur_mode]);
+
+ if (sc->cur_format == IIDC_FMT_VGA &&
+ sc->cur_mode < FWCAM_FMT0_V4L2_NMODES)
+ return (fwcam_fmt0_v4l2[sc->cur_mode].sizeimage);
/* Default to largest VGA mode */
return (FWCAM_MAX_FRAME_SIZE);
@@ -420,9 +460,7 @@
sc->frame_size = fwcam_frame_size(sc);
sc->frame_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO);
- sc->read_buf = malloc(sc->frame_size, M_FWCAM, M_WAITOK | M_ZERO);
sc->frame_offset = 0;
- sc->frame_ready = 0;
sc->frame_dropped = 0;
/* IIDC spec s3.1: set video mode registers before ISO enable */
@@ -519,9 +557,7 @@
xferq->hand = NULL;
free(sc->frame_buf, M_FWCAM);
- free(sc->read_buf, M_FWCAM);
sc->frame_buf = NULL;
- sc->read_buf = NULL;
sc->dma_ch = -1;
return (err);
@@ -553,9 +589,6 @@
FWCAM_LOCK(sc);
fw_iso_wait_inactive_locked(&sc->mtx, &sc->iso_active, "fwcamis");
- sc->frame_ready = 0;
- while (sc->read_in_progress)
- msleep(&sc->read_in_progress, &sc->mtx, PWAIT, "fwcamst", hz);
FWCAM_UNLOCK(sc);
xferq->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_OPEN | FWXFERQ_STREAM |
@@ -565,9 +598,23 @@
fw_iso_free_chunks(xferq, M_FWCAM);
free(sc->frame_buf, M_FWCAM);
- free(sc->read_buf, M_FWCAM);
sc->frame_buf = NULL;
- sc->read_buf = NULL;
+}
+
+static void
+fwcam_frame_done(struct fwcam_softc *sc)
+{
+ struct video_buf *vb;
+
+ vb = video_buf_acquire(sc->sc_vd);
+ if (vb == NULL)
+ return;
+
+ if (video_buf_write(vb, 0, sc->frame_buf, sc->frame_offset) != 0) {
+ video_buf_error(vb);
+ return;
+ }
+ video_buf_done(vb, sc->frame_offset, sc->sc_sequence++);
}
static void
@@ -579,7 +626,6 @@
struct mbuf *m;
uint8_t *payload;
uint32_t plen;
- uint8_t *tmp;
int dma_ch;
FWCAM_LOCK(sc);
@@ -606,25 +652,16 @@
}
if (fp->mode.stream.sy == 1) {
- if (sc->frame_offset > 0) {
- if (sc->frame_offset == sc->frame_size) {
- FWCAM_LOCK(sc);
- if (sc->read_in_progress) {
- sc->frame_dropped++;
- } else {
- if (sc->frame_ready)
- sc->frame_dropped++;
- tmp = sc->read_buf;
- sc->read_buf = sc->frame_buf;
- sc->frame_buf = tmp;
- sc->frame_ready = 1;
- wakeup(sc);
- selwakeup(&sc->rsel);
- }
- FWCAM_UNLOCK(sc);
- } else {
- sc->frame_dropped++;
- }
+ if (sc->frame_offset > 0 &&
+ sc->frame_offset == sc->frame_size) {
+ fwcam_frame_done(sc);
+ } else if (sc->frame_offset > 0) {
+ struct video_buf *vb;
+
+ vb = video_buf_acquire(sc->sc_vd);
+ if (vb != NULL)
+ video_buf_error(vb);
+ sc->frame_dropped++;
}
sc->frame_offset = 0;
}
@@ -641,6 +678,11 @@
memcpy(sc->frame_buf + sc->frame_offset, payload, plen);
sc->frame_offset += plen;
} else {
+ struct video_buf *vb;
+
+ vb = video_buf_acquire(sc->sc_vd);
+ if (vb != NULL)
+ video_buf_error(vb);
sc->frame_dropped++;
sc->frame_offset = 0;
}
@@ -652,131 +694,6 @@
&sc->dma_ch, dma_ch);
}
-static int
-fwcam_cdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
-{
- struct fwcam_softc *sc = dev->si_drv1;
- int err;
-
- FWCAM_LOCK(sc);
- if (sc->state == FWCAM_STATE_DETACHING) {
- FWCAM_UNLOCK(sc);
- return (ENXIO);
- }
-
- if (sc->state == FWCAM_STATE_IDLE) {
- sc->state = FWCAM_STATE_PROBING;
- FWCAM_UNLOCK(sc);
- taskqueue_enqueue(taskqueue_thread, &sc->probe_task);
- FWCAM_LOCK(sc);
- }
-
- while (sc->state == FWCAM_STATE_PROBING) {
- err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz);
- if (err) {
- FWCAM_UNLOCK(sc);
- return (err == EWOULDBLOCK ? ETIMEDOUT : err);
- }
- }
-
- if (sc->state != FWCAM_STATE_PROBED &&
- sc->state != FWCAM_STATE_STREAMING) {
- FWCAM_UNLOCK(sc);
- return (ENXIO);
- }
-
- sc->open_count++;
- FWCAM_UNLOCK(sc);
- return (0);
-}
-
-static int
-fwcam_cdev_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
- struct fwcam_softc *sc = dev->si_drv1;
-
- FWCAM_LOCK(sc);
- sc->open_count--;
- if (sc->open_count <= 0) {
- sc->open_count = 0;
- if (sc->state == FWCAM_STATE_STREAMING) {
- FWCAM_UNLOCK(sc);
- fwcam_iso_stop(sc);
- FWCAM_LOCK(sc);
- if (sc->state != FWCAM_STATE_DETACHING)
- sc->state = FWCAM_STATE_PROBED;
- }
- }
- FWCAM_UNLOCK(sc);
- return (0);
-}
-
-static int
-fwcam_cdev_read(struct cdev *dev, struct uio *uio, int ioflag)
-{
- struct fwcam_softc *sc = dev->si_drv1;
- int err;
-
- FWCAM_LOCK(sc);
- if (sc->state == FWCAM_STATE_PROBED) {
- FWCAM_UNLOCK(sc);
- err = fwcam_iso_start(sc);
- if (err)
- return (err);
- FWCAM_LOCK(sc);
- }
- while (!sc->frame_ready) {
- if (sc->state != FWCAM_STATE_STREAMING) {
- FWCAM_UNLOCK(sc);
- return (ENXIO);
- }
- if (ioflag & FNONBLOCK) {
- FWCAM_UNLOCK(sc);
- return (EAGAIN);
- }
- err = msleep(sc, &sc->mtx, PCATCH, "fwcamrd", 5 * hz);
- if (err) {
- FWCAM_UNLOCK(sc);
- return (err);
- }
- }
-
- sc->frame_ready = 0;
- if (sc->read_buf == NULL) {
- FWCAM_UNLOCK(sc);
- return (ENXIO);
- }
- sc->read_in_progress = 1;
- FWCAM_UNLOCK(sc);
-
- err = uiomove(sc->read_buf,
- MIN(uio->uio_resid, sc->frame_size), uio);
-
- FWCAM_LOCK(sc);
- sc->read_in_progress = 0;
- wakeup(&sc->read_in_progress);
- FWCAM_UNLOCK(sc);
-
- return (err);
-}
-
-static int
-fwcam_cdev_poll(struct cdev *dev, int events, struct thread *td)
-{
- struct fwcam_softc *sc = dev->si_drv1;
- int revents = 0;
-
- FWCAM_LOCK(sc);
- if (events & (POLLIN | POLLRDNORM)) {
- if (sc->frame_ready)
- revents |= events & (POLLIN | POLLRDNORM);
- else
- selrecord(td, &sc->rsel);
- }
- FWCAM_UNLOCK(sc);
- return (revents);
-}
-
static const uint32_t fwcam_feat_inq[] = {
[FWCAM_FEAT_BRIGHTNESS] = IIDC_BRIGHTNESS_INQ,
[FWCAM_FEAT_AUTO_EXPOSURE] = IIDC_AUTO_EXPOSURE_INQ,
@@ -812,6 +729,40 @@
[FWCAM_FEAT_TILT] = IIDC_TILT,
};
+/*
+ * Map IIDC feature IDs to V4L2 control IDs.
+ */
+static const uint32_t fwcam_feat_v4l2[] = {
+ [FWCAM_FEAT_BRIGHTNESS] = V4L2_CID_BRIGHTNESS,
+ [FWCAM_FEAT_AUTO_EXPOSURE] = V4L2_CID_EXPOSURE_AUTO,
+ [FWCAM_FEAT_SHARPNESS] = V4L2_CID_SHARPNESS,
+ [FWCAM_FEAT_WHITE_BALANCE] = V4L2_CID_AUTO_WHITE_BALANCE,
+ [FWCAM_FEAT_HUE] = V4L2_CID_HUE,
+ [FWCAM_FEAT_SATURATION] = V4L2_CID_SATURATION,
+ [FWCAM_FEAT_GAMMA] = V4L2_CID_GAMMA,
+ [FWCAM_FEAT_SHUTTER] = V4L2_CID_EXPOSURE_ABSOLUTE,
+ [FWCAM_FEAT_GAIN] = V4L2_CID_GAIN,
+ [FWCAM_FEAT_FOCUS] = V4L2_CID_FOCUS_ABSOLUTE,
+};
+
+#define FWCAM_V4L2_CTRL_COUNT nitems(fwcam_feat_v4l2)
+
+/*
+ * Find the IIDC feature ID for a V4L2 control ID.
+ * Returns -1 if not found.
+ */
+static int
+fwcam_find_feat_by_v4l2(uint32_t v4l2_id)
+{
+ int i;
+
+ for (i = 0; i < (int)FWCAM_V4L2_CTRL_COUNT; i++) {
+ if (fwcam_feat_v4l2[i] == v4l2_id)
+ return (i);
+ }
+ return (-1);
+}
+
static int
fwcam_get_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
{
@@ -889,111 +840,392 @@
return (fwcam_write_quadlet(sc, fwcam_feat_ctrl[feat->id], val));
}
+/*
+ * Ensure the camera has been probed (powered on, capabilities read).
+ * Called from hw callbacks that need device state.
+ */
static int
-fwcam_cdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
- int fflag, struct thread *td)
+fwcam_ensure_probed(struct fwcam_softc *sc)
{
- struct fwcam_softc *sc = dev->si_drv1;
- struct fwcam_mode *mode;
- struct fwcam_feature *feat;
- struct fwcam_info *info;
int err;
- if (sc->fwdev == NULL)
+ FWCAM_LOCK(sc);
+ if (sc->state == FWCAM_STATE_DETACHING) {
+ FWCAM_UNLOCK(sc);
return (ENXIO);
+ }
- switch (cmd) {
- case FWCAM_GMODE:
- mode = (struct fwcam_mode *)data;
- mode->format = sc->cur_format;
- mode->mode = sc->cur_mode;
- mode->framerate = sc->cur_framerate;
- mode->frame_size = sc->frame_size ?
- sc->frame_size : fwcam_frame_size(sc);
- return (0);
+ if (sc->state == FWCAM_STATE_IDLE) {
+ sc->state = FWCAM_STATE_PROBING;
+ FWCAM_UNLOCK(sc);
+ taskqueue_enqueue(taskqueue_thread, &sc->probe_task);
+ FWCAM_LOCK(sc);
+ }
+
+ while (sc->state == FWCAM_STATE_PROBING) {
+ err = msleep(sc, &sc->mtx, PCATCH, "fwcampr", 10 * hz);
+ if (err) {
+ FWCAM_UNLOCK(sc);
+ return (err == EWOULDBLOCK ? ETIMEDOUT : err);
+ }
+ }
+
+ if (sc->state != FWCAM_STATE_PROBED &&
+ sc->state != FWCAM_STATE_STREAMING) {
+ FWCAM_UNLOCK(sc);
+ return (ENXIO);
+ }
+
+ FWCAM_UNLOCK(sc);
+ return (0);
+}
+
+static int
+fwcam_hw_open(void *arg)
+{
+ struct fwcam_softc *sc = arg;
- case FWCAM_SMODE:
- {
- int was_streaming = 0;
+ return (fwcam_ensure_probed(sc));
+}
- mode = (struct fwcam_mode *)data;
- if (mode->format > 7 || mode->mode > 7 || mode->framerate > 7)
- return (EINVAL);
+static int
+fwcam_hw_querycap(void *arg, struct video_caps *caps)
+{
- if (!(sc->formats & (1 << (31 - mode->format))))
- return (EINVAL);
- if (!(sc->modes[mode->format] & (1 << (31 - mode->mode))))
- return (EINVAL);
- if (!(sc->rates[mode->format][mode->mode] &
- (1 << (31 - mode->framerate))))
- return (EINVAL);
+ bzero(caps, sizeof(*caps));
+ strlcpy(caps->driver, "fwcam", sizeof(caps->driver));
+ strlcpy(caps->card, "IIDC FireWire Camera", sizeof(caps->card));
+ strlcpy(caps->bus_info, "firewire", sizeof(caps->bus_info));
+ caps->version = (1 << 16) | (0 << 8) | 0; /* 1.0.0 */
+ caps->capabilities = VIDEO_CAP_CAPTURE |
+ VIDEO_CAP_READWRITE | VIDEO_CAP_STREAMING;
- FWCAM_LOCK(sc);
- if (sc->state == FWCAM_STATE_DETACHING) {
- FWCAM_UNLOCK(sc);
- return (ENXIO);
+ return (0);
+}
+
+/*
+ * Map a sequential enum index to an IIDC mode number.
+ * Returns -1 if index is out of range.
+ */
+static int
+fwcam_index_to_mode(struct fwcam_softc *sc, uint32_t index)
+{
+ int m;
+ uint32_t count = 0;
+
+ if (!(sc->formats & IIDC_FORMAT_VGA))
+ return (-1);
+
+ for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
+ if (sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))) {
+ if (count == index)
+ return (m);
+ count++;
}
- if (sc->state == FWCAM_STATE_STREAMING) {
- was_streaming = 1;
- FWCAM_UNLOCK(sc);
- fwcam_iso_stop(sc);
- FWCAM_LOCK(sc);
- if (sc->state != FWCAM_STATE_DETACHING)
- sc->state = FWCAM_STATE_PROBED;
+ }
+ return (-1);
+}
+
+static int
+fwcam_hw_enum_format(void *arg, uint32_t index, struct video_format *fmt)
+{
+ struct fwcam_softc *sc = arg;
+ const struct fwcam_v4l2_mode *vm;
+ int m;
+
+ m = fwcam_index_to_mode(sc, index);
+ if (m < 0)
+ return (EINVAL);
+
+ vm = &fwcam_fmt0_v4l2[m];
+
+ bzero(fmt, sizeof(*fmt));
+ fmt->pixelformat = vm->pixelformat;
+ fmt->width = vm->width;
+ fmt->height = vm->height;
+ fmt->bytesperline = vm->bytesperline;
+ fmt->sizeimage = vm->sizeimage;
+ fmt->field = V4L2_FIELD_NONE;
+
+ return (0);
+}
+
+static int
+fwcam_hw_get_format(void *arg, struct video_format *fmt)
+{
+ struct fwcam_softc *sc = arg;
+ const struct fwcam_v4l2_mode *vm;
+
+ if (sc->cur_format != IIDC_FMT_VGA ||
+ sc->cur_mode >= FWCAM_FMT0_V4L2_NMODES)
+ return (EIO);
+
+ vm = &fwcam_fmt0_v4l2[sc->cur_mode];
+
+ bzero(fmt, sizeof(*fmt));
+ fmt->pixelformat = vm->pixelformat;
+ fmt->width = vm->width;
+ fmt->height = vm->height;
+ fmt->bytesperline = vm->bytesperline;
+ fmt->sizeimage = vm->sizeimage;
+ fmt->field = V4L2_FIELD_NONE;
+
+ return (0);
+}
+
+/*
+ * Find the IIDC mode that best matches a V4L2 format request.
+ * Returns -1 if no match.
+ */
+static int
+fwcam_find_mode_for_format(struct fwcam_softc *sc,
+ const struct video_format *fmt)
+{
+ int m, best = -1;
+
+ if (!(sc->formats & IIDC_FORMAT_VGA))
+ return (-1);
+
+ for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
+ if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
+ continue;
+ if (fwcam_fmt0_v4l2[m].pixelformat == fmt->pixelformat &&
+ fwcam_fmt0_v4l2[m].width == fmt->width &&
+ fwcam_fmt0_v4l2[m].height == fmt->height) {
+ best = m;
+ break;
}
- FWCAM_UNLOCK(sc);
+ }
- err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
- (uint32_t)mode->format << IIDC_CUR_V_SHIFT);
- if (err == 0)
- err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
- (uint32_t)mode->mode << IIDC_CUR_V_SHIFT);
- if (err == 0)
- err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
- (uint32_t)mode->framerate << IIDC_CUR_V_SHIFT);
-
- if (err == 0) {
- sc->cur_format = mode->format;
- sc->cur_mode = mode->mode;
- sc->cur_framerate = mode->framerate;
- mode->frame_size = fwcam_frame_size(sc);
+ /* If exact match failed, try matching just pixelformat */
+ if (best < 0) {
+ for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
+ if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
+ continue;
+ if (fwcam_fmt0_v4l2[m].pixelformat ==
+ fmt->pixelformat) {
+ best = m;
+ break;
+ }
}
+ }
- if (was_streaming)
- fwcam_iso_start(sc);
- return (err);
- }
-
- case FWCAM_GFEAT:
- feat = (struct fwcam_feature *)data;
- return (fwcam_get_feature(sc, feat));
-
- case FWCAM_SFEAT:
- feat = (struct fwcam_feature *)data;
- return (fwcam_set_feature(sc, feat));
-
- case FWCAM_GINFO:
- info = (struct fwcam_info *)data;
- info->formats = sc->formats;
- info->basic_func = sc->basic_func;
- info->features_hi = sc->features_hi;
- info->features_lo = sc->features_lo;
- info->cur_format = sc->cur_format;
- info->cur_mode = sc->cur_mode;
- info->cur_framerate = sc->cur_framerate;
- info->state = sc->state;
- info->frame_size = sc->frame_size ?
- sc->frame_size : fwcam_frame_size(sc);
- info->frame_dropped = sc->frame_dropped;
- info->iso_channel = sc->iso_channel;
- info->_pad[0] = info->_pad[1] = info->_pad[2] = 0;
- return (0);
+ return (best);
+}
+
+static int
+fwcam_hw_try_format(void *arg, struct video_format *fmt)
+{
+ struct fwcam_softc *sc = arg;
+ const struct fwcam_v4l2_mode *vm;
+ int m;
+
+ m = fwcam_find_mode_for_format(sc, fmt);
+ if (m < 0)
+ return (EINVAL);
+
+ vm = &fwcam_fmt0_v4l2[m];
+
+ fmt->pixelformat = vm->pixelformat;
+ fmt->width = vm->width;
+ fmt->height = vm->height;
+ fmt->bytesperline = vm->bytesperline;
+ fmt->sizeimage = vm->sizeimage;
+ fmt->field = V4L2_FIELD_NONE;
+
+ return (0);
+}
+
+static int
+fwcam_hw_set_format(void *arg, const struct video_format *fmt)
+{
+ struct fwcam_softc *sc = arg;
+ int m, err;
+
+ m = fwcam_find_mode_for_format(sc, fmt);
+ if (m < 0)
+ return (EINVAL);
+
+ if (!(sc->rates[IIDC_FMT_VGA][m] &
+ (1 << (31 - sc->cur_framerate)))) {
+ /* Current framerate not supported in new mode, pick first */
+ int r;
+ for (r = 0; r < 8; r++) {
+ if (sc->rates[IIDC_FMT_VGA][m] & (1 << (31 - r))) {
+ sc->cur_framerate = r;
+ break;
+ }
+ }
+ }
+
+ err = fwcam_write_quadlet(sc, IIDC_CUR_V_FORMAT,
+ (uint32_t)IIDC_FMT_VGA << IIDC_CUR_V_SHIFT);
+ if (err == 0)
+ err = fwcam_write_quadlet(sc, IIDC_CUR_V_MODE,
+ (uint32_t)m << IIDC_CUR_V_SHIFT);
+ if (err == 0)
+ err = fwcam_write_quadlet(sc, IIDC_CUR_V_FRM_RATE,
+ (uint32_t)sc->cur_framerate << IIDC_CUR_V_SHIFT);
+
+ if (err == 0) {
+ sc->cur_format = IIDC_FMT_VGA;
+ sc->cur_mode = m;
+ }
+
+ return (err);
+}
+
+static int
+fwcam_hw_enum_framesizes(void *arg, struct video_frmsizeenum *fse)
+{
+ struct fwcam_softc *sc = arg;
+ int m;
+ uint32_t count = 0;
- default:
- return (ENOTTY);
+ if (!(sc->formats & IIDC_FORMAT_VGA))
+ return (EINVAL);
+
+ for (m = 0; m < (int)FWCAM_FMT0_V4L2_NMODES; m++) {
+ if (!(sc->modes[IIDC_FMT_VGA] & (1 << (31 - m))))
+ continue;
+ if (fwcam_fmt0_v4l2[m].pixelformat != fse->pixelformat)
+ continue;
+ if (count == fse->index) {
+ fse->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fse->discrete.width = fwcam_fmt0_v4l2[m].width;
+ fse->discrete.height = fwcam_fmt0_v4l2[m].height;
+ return (0);
+ }
+ count++;
}
+
+ return (EINVAL);
}
+static int
+fwcam_hw_enum_input(void *arg, uint32_t index, struct video_input *inp)
+{
+
+ if (index != 0)
+ return (EINVAL);
+
+ bzero(inp, sizeof(*inp));
+ inp->index = 0;
+ strlcpy(inp->name, "IIDC Camera", sizeof(inp->name));
+ inp->type = VIDEO_INPUT_TYPE_CAMERA;
+
+ return (0);
+}
+
+static int
+fwcam_hw_get_input(void *arg, uint32_t *index)
+{
+
+ *index = 0;
+ return (0);
+}
+
+static int
+fwcam_hw_set_input(void *arg, uint32_t index)
+{
+
+ if (index != 0)
+ return (EINVAL);
+ return (0);
+}
+
+static int
+fwcam_hw_query_control(void *arg, struct video_control_desc *qc)
+{
+ struct fwcam_softc *sc = arg;
+ struct fwcam_feature feat;
+ int fid;
+
+ fid = fwcam_find_feat_by_v4l2(qc->id);
+ if (fid < 0)
+ return (EINVAL);
+
+ feat.id = fid;
+ if (fwcam_get_feature(sc, &feat) != 0)
+ return (EINVAL);
+
+ if (!(feat.flags & FWCAM_FEATF_PRESENT))
+ return (EINVAL);
+
+ qc->type = V4L2_CTRL_TYPE_INTEGER;
+ strlcpy(qc->name, fwcam_feat_names[fid], sizeof(qc->name));
+ qc->minimum = feat.min;
+ qc->maximum = feat.max;
+ qc->step = 1;
+ qc->default_value = feat.min;
+ qc->flags = 0;
+
+ return (0);
+}
+
+static int
+fwcam_hw_get_control(void *arg, struct video_control *ctrl)
+{
+ struct fwcam_softc *sc = arg;
+ struct fwcam_feature feat;
+ int fid;
+
+ fid = fwcam_find_feat_by_v4l2(ctrl->id);
+ if (fid < 0)
+ return (EINVAL);
+
+ feat.id = fid;
+ if (fwcam_get_feature(sc, &feat) != 0)
+ return (EINVAL);
+
+ ctrl->value = feat.value;
+ return (0);
+}
+
+static int
+fwcam_hw_set_control(void *arg, const struct video_control *ctrl)
+{
+ struct fwcam_softc *sc = arg;
+ struct fwcam_feature feat;
+ int fid;
+
+ fid = fwcam_find_feat_by_v4l2(ctrl->id);
+ if (fid < 0)
+ return (EINVAL);
+
+ feat.id = fid;
+ feat.value = ctrl->value;
+ feat.value2 = 0;
+ return (fwcam_set_feature(sc, &feat));
+}
+
+static int
+fwcam_hw_start_stream(void *arg)
+{
+ struct fwcam_softc *sc = arg;
+ int err;
+
+ err = fwcam_ensure_probed(sc);
+ if (err)
+ return (err);
+
+ sc->sc_sequence = 0;
+
+ return (fwcam_iso_start(sc));
+}
+
+static void
+fwcam_hw_stop_stream(void *arg)
+{
+ struct fwcam_softc *sc = arg;
+
+ fwcam_iso_stop(sc);
+
+ FWCAM_LOCK(sc);
+ if (sc->state != FWCAM_STATE_DETACHING)
+ sc->state = FWCAM_STATE_PROBED;
+ FWCAM_UNLOCK(sc);
+}
static int
fwcam_probe(device_t dev)
@@ -1021,6 +1253,7 @@
struct fwcam_softc *sc;
struct fw_unit *unit;
uint32_t cmd_base;
+ int err;
unit = fw_get_unit(dev);
if (unit == NULL || unit->fwdev == NULL)
@@ -1044,13 +1277,15 @@
sc->state = FWCAM_STATE_IDLE;
sc->dma_ch = -1;
sc->iso_active = 0;
- sc->open_count = 0;
- knlist_init_mtx(&sc->rsel.si_note, &sc->mtx);
+ sc->sc_sequence = 0;
TASK_INIT(&sc->probe_task, 0, fwcam_probe_task, sc);
- sc->cdev = make_dev(&fwcam_cdevsw, device_get_unit(dev),
- UID_ROOT, GID_OPERATOR, 0660, "fwcam%d", device_get_unit(dev));
- sc->cdev->si_drv1 = sc;
+ err = video_register(dev, &fwcam_hw_ops, sc, &sc->sc_vd);
+ if (err != 0) {
+ device_printf(dev, "failed to register video device\n");
+ mtx_destroy(&sc->mtx);
+ return (err);
+ }
return (0);
}
@@ -1062,20 +1297,17 @@
sc = device_get_softc(dev);
+ if (sc->sc_vd != NULL)
+ video_unregister(sc->sc_vd);
+
FWCAM_LOCK(sc);
sc->state = FWCAM_STATE_DETACHING;
- wakeup(sc); /* wake any sleeping readers */
+ wakeup(sc);
FWCAM_UNLOCK(sc);
taskqueue_drain(taskqueue_thread, &sc->probe_task);
fwcam_iso_stop(sc);
- if (sc->cdev != NULL)
- destroy_dev(sc->cdev);
-
- seldrain(&sc->rsel);
- knlist_destroy(&sc->rsel.si_note);
-
FWCAM_LOCK(sc);
sc->fwdev = NULL;
FWCAM_UNLOCK(sc);
@@ -1102,3 +1334,4 @@
DRIVER_MODULE(fwcam, firewire, fwcam_driver, 0, 0);
MODULE_VERSION(fwcam, 1);
MODULE_DEPEND(fwcam, firewire, 1, 1, 1);
+MODULE_DEPEND(fwcam, video, 1, 1, 1);
diff --git a/sys/dev/usb/video/uvideo_v4l2.h b/sys/dev/usb/video/uvideo_v4l2.h
--- a/sys/dev/usb/video/uvideo_v4l2.h
+++ b/sys/dev/usb/video/uvideo_v4l2.h
@@ -365,6 +365,8 @@
/* Luminance+Chrominance formats */
#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V')
#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y')
+#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4')
+#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P')
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2')
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1')
#define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0')
@@ -383,6 +385,7 @@
#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ')
/* RGB formats */
+#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3')
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P')
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3')
#define V4L2_PIX_FMT_XBGR32 v4l2_fourcc('X', 'R', '2', '4')
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jul 30, 10:30 AM (10 h, 10 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35710382
Default Alt Text
D58369.id182736.diff (27 KB)
Attached To
Mode
D58369: fwcam: convert to video(4) framework
Attached
Detach File
Event Timeline
Log In to Comment