mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
fwcam: convert to video(4) framework
Replaced the monolithic cdevsw implementation with the video(4) framework. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D58369
This commit is contained in:
1 parent
8cdcf4b27c
commit
f5dc2263ab
4 files changed
+551
-312
No files matched your search
+16
-12
@@ -3,7 +3,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: BSD-2-Clause
|
||||
.\"
|
||||
.Dd July 12, 2026
|
||||
.Dd July 27, 2026
|
||||
.Dt FWCAM 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -11,6 +11,7 @@
|
||||
.Nd IIDC FireWire digital camera driver
|
||||
.Sh SYNOPSIS
|
||||
.Cd "device firewire"
|
||||
.Cd "device video"
|
||||
.Cd "device fwcam"
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
@@ -31,12 +32,13 @@ Camera hardware probing is deferred until the device is first opened.
|
||||
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 +111,16 @@ Can be set as a tunable in
|
||||
.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.
|
||||
|
||||
+525
-292
@@ -16,17 +16,13 @@
|
||||
#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 <sys/videoio.h>
|
||||
|
||||
#include <dev/firewire/firewire.h>
|
||||
#include <dev/firewire/firewirereg.h>
|
||||
@@ -34,6 +30,10 @@
|
||||
#include <dev/firewire/fwcam.h>
|
||||
#include <dev/firewire/fw_helpers.h>
|
||||
|
||||
#include <dev/video/video.h>
|
||||
|
||||
#include "video_if.h"
|
||||
|
||||
static MALLOC_DEFINE(M_FWCAM, "fwcam", "IIDC FireWire Camera");
|
||||
|
||||
static int debug = 0;
|
||||
@@ -59,24 +59,54 @@ static void fwcam_probe_task(void *, int);
|
||||
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 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 int fwcam_hw_open(device_t);
|
||||
static int fwcam_hw_querycap(device_t, struct video_caps *);
|
||||
static int fwcam_hw_enum_format(device_t, uint32_t, struct video_format *);
|
||||
static int fwcam_hw_get_format(device_t, struct video_format *);
|
||||
static int fwcam_hw_try_format(device_t, struct video_format *);
|
||||
static int fwcam_hw_set_format(device_t, const struct video_format *);
|
||||
static int fwcam_hw_enum_framesizes(device_t, struct video_frmsizeenum *);
|
||||
static int fwcam_hw_enum_input(device_t, uint32_t, struct video_input *);
|
||||
static int fwcam_hw_get_input(device_t, uint32_t *);
|
||||
static int fwcam_hw_set_input(device_t, uint32_t);
|
||||
static int fwcam_hw_query_control(device_t, struct video_control_desc *);
|
||||
static int fwcam_hw_get_control(device_t, struct video_control *);
|
||||
static int fwcam_hw_set_control(device_t, const struct video_control *);
|
||||
static int fwcam_hw_start_stream(device_t);
|
||||
static void fwcam_hw_stop_stream(device_t);
|
||||
|
||||
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 +377,10 @@ fwcam_probe_task(void *arg, int pending __unused)
|
||||
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 +443,7 @@ fwcam_iso_start(struct fwcam_softc *sc)
|
||||
|
||||
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 +540,7 @@ fail:
|
||||
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 +572,6 @@ fwcam_iso_stop(struct fwcam_softc *sc)
|
||||
|
||||
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 +581,23 @@ fwcam_iso_stop(struct fwcam_softc *sc)
|
||||
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 +609,6 @@ fwcam_iso_input(struct fw_xferq *xferq)
|
||||
struct mbuf *m;
|
||||
uint8_t *payload;
|
||||
uint32_t plen;
|
||||
uint8_t *tmp;
|
||||
int dma_ch;
|
||||
|
||||
FWCAM_LOCK(sc);
|
||||
@@ -606,25 +635,16 @@ fwcam_iso_input(struct fw_xferq *xferq)
|
||||
}
|
||||
|
||||
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 +661,11 @@ fwcam_iso_input(struct fw_xferq *xferq)
|
||||
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 +677,6 @@ fwcam_iso_input(struct fw_xferq *xferq)
|
||||
&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 +712,40 @@ static const uint32_t fwcam_feat_ctrl[] = {
|
||||
[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 +823,392 @@ fwcam_set_feature(struct fwcam_softc *sc, struct fwcam_feature *feat)
|
||||
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)
|
||||
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);
|
||||
|
||||
case FWCAM_SMODE:
|
||||
{
|
||||
int was_streaming = 0;
|
||||
|
||||
mode = (struct fwcam_mode *)data;
|
||||
if (mode->format > 7 || mode->mode > 7 || mode->framerate > 7)
|
||||
return (EINVAL);
|
||||
|
||||
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);
|
||||
|
||||
FWCAM_LOCK(sc);
|
||||
if (sc->state == FWCAM_STATE_DETACHING) {
|
||||
FWCAM_UNLOCK(sc);
|
||||
return (ENXIO);
|
||||
}
|
||||
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;
|
||||
}
|
||||
FWCAM_LOCK(sc);
|
||||
if (sc->state == FWCAM_STATE_DETACHING) {
|
||||
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 (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);
|
||||
|
||||
default:
|
||||
return (ENOTTY);
|
||||
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);
|
||||
}
|
||||
|
||||
FWCAM_UNLOCK(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_open(device_t dev)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
|
||||
return (fwcam_ensure_probed(sc));
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_querycap(device_t dev, struct video_caps *caps)
|
||||
{
|
||||
|
||||
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;
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_enum_format(device_t dev, uint32_t index, struct video_format *fmt)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev, struct video_format *fmt)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (best);
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_try_format(device_t dev, struct video_format *fmt)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev, const struct video_format *fmt)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev, struct video_frmsizeenum *fse)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
int m;
|
||||
uint32_t count = 0;
|
||||
|
||||
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(device_t dev, 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(device_t dev, uint32_t *index)
|
||||
{
|
||||
|
||||
*index = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_set_input(device_t dev, uint32_t index)
|
||||
{
|
||||
|
||||
if (index != 0)
|
||||
return (EINVAL);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
fwcam_hw_query_control(device_t dev, struct video_control_desc *qc)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev, struct video_control *ctrl)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev, const struct video_control *ctrl)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
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(device_t dev)
|
||||
{
|
||||
struct fwcam_softc *sc = device_get_softc(dev);
|
||||
|
||||
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 +1236,7 @@ fwcam_attach(device_t dev)
|
||||
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 +1260,15 @@ fwcam_attach(device_t dev)
|
||||
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, &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 +1280,17 @@ fwcam_detach(device_t dev)
|
||||
|
||||
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);
|
||||
@@ -1090,6 +1305,23 @@ static device_method_t fwcam_methods[] = {
|
||||
DEVMETHOD(device_attach, fwcam_attach),
|
||||
DEVMETHOD(device_detach, fwcam_detach),
|
||||
|
||||
/* video(4) interface */
|
||||
DEVMETHOD(video_open, fwcam_hw_open),
|
||||
DEVMETHOD(video_querycap, fwcam_hw_querycap),
|
||||
DEVMETHOD(video_enum_format, fwcam_hw_enum_format),
|
||||
DEVMETHOD(video_get_format, fwcam_hw_get_format),
|
||||
DEVMETHOD(video_try_format, fwcam_hw_try_format),
|
||||
DEVMETHOD(video_set_format, fwcam_hw_set_format),
|
||||
DEVMETHOD(video_enum_framesizes, fwcam_hw_enum_framesizes),
|
||||
DEVMETHOD(video_enum_input, fwcam_hw_enum_input),
|
||||
DEVMETHOD(video_get_input, fwcam_hw_get_input),
|
||||
DEVMETHOD(video_set_input, fwcam_hw_set_input),
|
||||
DEVMETHOD(video_query_control, fwcam_hw_query_control),
|
||||
DEVMETHOD(video_get_control, fwcam_hw_get_control),
|
||||
DEVMETHOD(video_set_control, fwcam_hw_set_control),
|
||||
DEVMETHOD(video_start_stream, fwcam_hw_start_stream),
|
||||
DEVMETHOD(video_stop_stream, fwcam_hw_stop_stream),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
||||
@@ -1102,3 +1334,4 @@ static driver_t fwcam_driver = {
|
||||
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);
|
||||
@@ -281,10 +281,16 @@ static const struct fwcam_fmt0_mode fwcam_fmt0_modes[FWCAM_FMT0_NMODES] = {
|
||||
#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 @@ struct fwcam_softc {
|
||||
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;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# Makefile for the IIDC 1394-based Digital Camera driver
|
||||
|
||||
.PATH: ${SRCTOP}/sys/dev/firewire
|
||||
.PATH: ${SRCTOP}/sys/dev/firewire ${SRCTOP}/sys/dev/video
|
||||
|
||||
KMOD = fwcam
|
||||
SRCS = bus_if.h device_if.h \
|
||||
video_if.h \
|
||||
fwcam.c fwcam.h fw_helpers.h \
|
||||
firewire.h firewirereg.h \
|
||||
iec13213.h
|
||||
|
||||
Reference in new issue
Block a user