#include <linux/version.h>
#include <linux/mm.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
#include "em28xx.h"
#include <media/v4l2-common.h>
if ((char *)startwrite + lencopy > (char *)outp +
buf->vb.size) {
- em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end"
+ "(2)\n",
((char *)startwrite + lencopy) -
((char *)outp + buf->vb.size));
lencopy = remain = (char *)outp + buf->vb.size -
{
void *startwrite, *startread;
int offset;
- int bytesperline = 720;
+ int bytesperline = dev->vbi_width;
if (dev == NULL) {
- printk("dev is null\n");
+ em28xx_isocdbg("dev is null\n");
return;
}
if (dma_q == NULL) {
- printk("dma_q is null\n");
+ em28xx_isocdbg("dma_q is null\n");
return;
}
if (buf == NULL) {
return;
}
if (p == NULL) {
- printk("p is null\n");
+ em28xx_isocdbg("p is null\n");
return;
}
if (outp == NULL) {
- printk("outp is null\n");
+ em28xx_isocdbg("outp is null\n");
return;
}
/* Make sure the bottom field populates the second half of the frame */
if (buf->top_field == 0) {
- startwrite += bytesperline * 0x0c;
- offset += bytesperline * 0x0c;
+ startwrite += bytesperline * dev->vbi_height;
+ offset += bytesperline * dev->vbi_height;
}
memcpy(startwrite, startread, len);
dev->cur_field = p[2];
}
- /* FIXME: get rid of hard-coded value */
- vbi_size = 720 * 0x0c;
+ vbi_size = dev->vbi_width * dev->vbi_height;
if (dev->capture_type == 0) {
if (dev->vbi_read >= vbi_size) {
/* We've already read all the VBI data, so
treat the rest as video */
- printk("djh c should never happen\n");
+ em28xx_isocdbg("dev->vbi_read > vbi_size\n");
} else if ((dev->vbi_read + len) < vbi_size) {
/* This entire frame is VBI data */
if (dev->vbi_read == 0 &&
vbi_get_next_buf(vbi_dma_q, &vbi_buf);
if (vbi_buf == NULL)
vbioutp = NULL;
- else {
- vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
- }
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
}
if (dev->vbi_read == 0) {
struct em28xx *dev = fh->dev;
struct v4l2_frequency f;
- *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+ *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)
+ >> 3;
if (0 == *count)
*count = EM28XX_DEF_BUF;
struct em28xx *dev = fh->dev;
int rc = 0, urb_init = 0;
- buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+ buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth
+ + 7) >> 3;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
}
/* Usage lock check functions */
-static int res_get(struct em28xx_fh *fh)
+static int res_get(struct em28xx_fh *fh, unsigned int bit)
{
struct em28xx *dev = fh->dev;
- int rc = 0;
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
- if (dev->stream_on)
- return -EBUSY;
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ em28xx_videodbg("res: get %d\n", bit);
+ mutex_unlock(&dev->lock);
+ return 1;
+}
- dev->stream_on = 1;
- fh->stream_on = 1;
- return rc;
+static int res_check(struct em28xx_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
}
-static int res_check(struct em28xx_fh *fh)
+static int res_locked(struct em28xx *dev, unsigned int bit)
{
- return fh->stream_on;
+ return dev->resources & bit;
}
-static void res_free(struct em28xx_fh *fh)
+static void res_free(struct em28xx_fh *fh, unsigned int bits)
{
struct em28xx *dev = fh->dev;
- fh->stream_on = 0;
- dev->stream_on = 0;
+ BUG_ON((fh->resources & bits) != bits);
+
+ mutex_lock(&dev->lock);
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ em28xx_videodbg("res: put %d\n", bits);
+ mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct em28xx_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return EM28XX_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return EM28XX_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
}
/*
/* the em2800 can only scale down to 50% */
height = height > (3 * maxh / 4) ? maxh : maxh / 2;
width = width > (3 * maxw / 4) ? maxw : maxw / 2;
- /* According to empiatech support the MaxPacketSize is too small
- * to support framesizes larger than 640x480 @ 30 fps or 640x576
- * @ 25 fps. As this would cut of a part of the image we prefer
- * 360x576 or 360x480 for now */
- if (width == maxw && height == maxh)
- width /= 2;
} else {
/* width must even because of the YUYV format
height must be even because of interlacing */
- v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
+ v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
+ 1, 0);
}
get_scale(dev, width, height, &hscale, &vscale);
goto out;
}
- if (dev->stream_on && !fh->stream_on) {
- em28xx_errdev("%s device in use by another fh\n", __func__);
- rc = -EBUSY;
- goto out;
- }
-
rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
f->fmt.pix.width, f->fmt.pix.height);
return rc;
}
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ *norm = dev->norm;
+
+ return 0;
+}
+
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct em28xx_fh *fh = priv;
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc;
+ int rc = -EINVAL;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ if (unlikely(type != fh->type))
+ return -EINVAL;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
+ em28xx_videodbg("vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
- if (likely(rc >= 0)) {
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vidq);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_streamon(&fh->vb_vbiq);
- }
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
- mutex_unlock(&dev->lock);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vidq);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_streamon(&fh->vb_vbiq);
return rc;
}
if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
+ em28xx_videodbg("vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
videobuf_streamoff(&fh->vb_vidq);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
videobuf_streamoff(&fh->vb_vbiq);
-
- res_free(fh);
-
- mutex_unlock(&dev->lock);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
return 0;
}
cap->version = EM28XX_VERSION_CODE;
cap->capabilities =
- V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_SLICED_VBI_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ if (dev->vbi_dev)
+ cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
+
if (dev->audio_mode.has_audio)
cap->capabilities |= V4L2_CAP_AUDIO;
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- format->fmt.vbi.samples_per_line = 720;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */
- /* FIXME: hard-coded for NTSC support */
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
- format->fmt.vbi.count[0] = 12;
- format->fmt.vbi.count[1] = 12;
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
return 0;
}
static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- format->fmt.vbi.samples_per_line = 720;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
/* Varies by video standard (NTSC, PAL, etc.) */
- /* FIXME: hard-coded for NTSC support */
- format->fmt.vbi.sampling_rate = 6750000 * 4 / 2; /* FIXME: ??? */
- format->fmt.vbi.count[0] = 12;
- format->fmt.vbi.count[1] = 12;
- format->fmt.vbi.start[0] = 10;
- format->fmt.vbi.start[1] = 273;
+ if (dev->norm & V4L2_STD_525_60) {
+ /* NTSC */
+ format->fmt.vbi.start[0] = 10;
+ format->fmt.vbi.start[1] = 273;
+ } else if (dev->norm & V4L2_STD_625_50) {
+ /* PAL */
+ format->fmt.vbi.start[0] = 6;
+ format->fmt.vbi.start[1] = 318;
+ }
return 0;
}
At a minimum, it causes a crash in zvbi since it does
a memcpy based on the source buffer length */
int result = videobuf_querybuf(&fh->vb_vbiq, b);
- b->length = 17280;
+ b->length = dev->vbi_width * dev->vbi_height * 2;
+
return result;
}
}
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
return videobuf_qbuf(&fh->vb_vidq, b);
- else {
+ else
return videobuf_qbuf(&fh->vb_vbiq, b);
- }
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
*/
static int em28xx_v4l2_open(struct file *filp)
{
- int minor = video_devdata(filp)->minor;
- int errCode = 0, radio;
- struct em28xx *dev;
- enum v4l2_buf_type fh_type;
+ int errCode = 0, radio = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct em28xx *dev = video_drvdata(filp);
+ enum v4l2_buf_type fh_type = 0;
struct em28xx_fh *fh;
enum v4l2_field field;
- dev = em28xx_get_device(minor, &fh_type, &radio);
-
- if (NULL == dev)
- return -ENODEV;
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ break;
+ case VFL_TYPE_RADIO:
+ radio = 1;
+ break;
+ }
mutex_lock(&dev->lock);
- em28xx_videodbg("open minor=%d type=%s users=%d\n",
- minor, v4l2_type_names[fh_type], dev->users);
+ em28xx_videodbg("open dev=%s type=%s users=%d\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type],
+ dev->users);
fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
else
field = V4L2_FIELD_INTERLACED;
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
- NULL, &dev->slock, fh->type, field,
- sizeof(struct em28xx_buffer), fh);
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
+ sizeof(struct em28xx_buffer), fh);
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct em28xx_buffer), fh);
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct em28xx_buffer), fh);
mutex_unlock(&dev->lock);
/*FIXME: I2C IR should be disconnected */
if (dev->radio_dev) {
- if (-1 != dev->radio_dev->minor)
+ if (video_is_registered(dev->radio_dev))
video_unregister_device(dev->radio_dev);
else
video_device_release(dev->radio_dev);
dev->radio_dev = NULL;
}
if (dev->vbi_dev) {
- em28xx_info("V4L2 device /dev/vbi%d deregistered\n",
- dev->vbi_dev->num);
- if (-1 != dev->vbi_dev->minor)
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vbi_dev));
+ if (video_is_registered(dev->vbi_dev))
video_unregister_device(dev->vbi_dev);
else
video_device_release(dev->vbi_dev);
dev->vbi_dev = NULL;
}
if (dev->vdev) {
- em28xx_info("V4L2 device /dev/video%d deregistered\n",
- dev->vdev->num);
- if (-1 != dev->vdev->minor)
+ em28xx_info("V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vdev));
+ if (video_is_registered(dev->vdev))
video_unregister_device(dev->vdev);
else
video_device_release(dev->vdev);
em28xx_videodbg("users=%d\n", dev->users);
-
- mutex_lock(&dev->lock);
- if (res_check(fh))
- res_free(fh);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 1) {
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
+
+ if (dev->users == 1) {
/* the device is already disconnect,
free the remaining resources */
if (dev->state & DEV_DISCONNECTED) {
em28xx_release_resources(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
return 0;
}
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
/* do this before setting alternate! */
em28xx_uninit_isoc(dev);
}
}
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_stop(&fh->vb_vbiq);
- videobuf_mmap_free(&fh->vb_vbiq);
- }
-
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
return 0;
}
*/
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
+ if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
+ return -EBUSY;
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ return -EBUSY;
return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return POLLERR;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VIDEO))
+ return POLLERR;
return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, EM28XX_RESOURCE_VBI))
+ return POLLERR;
return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- else
+ } else {
return POLLERR;
+ }
}
/*
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
-
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
- .minor = -1,
-
.tvnorms = V4L2_STD_ALL,
- /* FIXME: we need this to be NTSC for VBI to work - it should
- be moved to a per-board definition */
- .current_norm = V4L2_STD_NTSC,
+ .current_norm = V4L2_STD_PAL,
};
static const struct v4l2_file_operations radio_fops = {
.name = "em28xx-radio",
.fops = &radio_fops,
.ioctl_ops = &radio_ioctl_ops,
- .minor = -1,
};
/******************************** usb interface ******************************/
return NULL;
*vfd = *template;
- vfd->minor = -1;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
+ video_set_drvdata(vfd, dev);
return vfd;
}
dev->mute = 1;
dev->volume = 0x1f;
- /* enable vbi capturing */
-
/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
em28xx_write_reg(dev, EM28XX_R0F_XCLK,
(EM28XX_XCLK_AUDIO_UNMUTE | val));
- em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x51);
em28xx_set_outfmt(dev);
em28xx_colorlevels_set_default(dev);
}
/* Allocate and fill vbi video_device struct */
- dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi");
+ if (em28xx_vbi_supported(dev) == 1) {
+ dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+ "vbi");
- /* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
- vbi_nr[dev->devno]);
- if (ret < 0) {
- em28xx_errdev("unable to register vbi device\n");
- return ret;
+ /* register v4l2 vbi video_device */
+ ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ vbi_nr[dev->devno]);
+ if (ret < 0) {
+ em28xx_errdev("unable to register vbi device\n");
+ return ret;
+ }
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
em28xx_errdev("can't register radio device\n");
return ret;
}
- em28xx_info("Registered radio device as /dev/radio%d\n",
- dev->radio_dev->num);
+ em28xx_info("Registered radio device as %s\n",
+ video_device_node_name(dev->radio_dev));
}
- em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
- dev->vdev->num, dev->vbi_dev->num);
+ em28xx_info("V4L2 video device registered as %s\n",
+ video_device_node_name(dev->vdev));
+
+ if (dev->vbi_dev)
+ em28xx_info("V4L2 VBI device registered as %s\n",
+ video_device_node_name(dev->vbi_dev));
return 0;
}