|
@@ -33,12 +33,13 @@
|
|
|
#include <linux/videodev.h>
|
|
|
#endif
|
|
|
#include <linux/interrupt.h>
|
|
|
-#include <media/videobuf-vmalloc.h>
|
|
|
-#include <media/v4l2-common.h>
|
|
|
-#include <media/v4l2-ioctl.h>
|
|
|
#include <linux/kthread.h>
|
|
|
#include <linux/highmem.h>
|
|
|
#include <linux/freezer.h>
|
|
|
+#include <media/videobuf-vmalloc.h>
|
|
|
+#include <media/v4l2-device.h>
|
|
|
+#include <media/v4l2-ioctl.h>
|
|
|
+#include "font.h"
|
|
|
|
|
|
#define VIVI_MODULE_NAME "vivi"
|
|
|
|
|
@@ -47,18 +48,32 @@
|
|
|
#define WAKE_DENOMINATOR 1001
|
|
|
#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
|
|
|
|
|
|
-#include "font.h"
|
|
|
-
|
|
|
#define VIVI_MAJOR_VERSION 0
|
|
|
-#define VIVI_MINOR_VERSION 5
|
|
|
+#define VIVI_MINOR_VERSION 6
|
|
|
#define VIVI_RELEASE 0
|
|
|
#define VIVI_VERSION \
|
|
|
KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
|
|
|
|
|
|
-/* Declare static vars that will be used as parameters */
|
|
|
-static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
|
|
|
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
|
|
|
-static int n_devs = 1; /* Number of virtual devices */
|
|
|
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
|
|
|
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
|
|
|
+MODULE_LICENSE("Dual BSD/GPL");
|
|
|
+
|
|
|
+static unsigned video_nr = -1;
|
|
|
+module_param(video_nr, uint, 0644);
|
|
|
+MODULE_PARM_DESC(video_nr, "videoX start number, -1 is autodetect");
|
|
|
+
|
|
|
+static unsigned n_devs = 1;
|
|
|
+module_param(n_devs, uint, 0644);
|
|
|
+MODULE_PARM_DESC(n_devs, "number of video devices to create");
|
|
|
+
|
|
|
+static unsigned debug;
|
|
|
+module_param(debug, uint, 0644);
|
|
|
+MODULE_PARM_DESC(debug, "activates debug info");
|
|
|
+
|
|
|
+static unsigned int vid_limit = 16;
|
|
|
+module_param(vid_limit, uint, 0644);
|
|
|
+MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
|
|
|
+
|
|
|
|
|
|
/* supported controls */
|
|
|
static struct v4l2_queryctrl vivi_qctrl[] = {
|
|
@@ -112,11 +127,8 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
|
|
|
|
|
|
static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
|
|
|
|
|
|
-#define dprintk(dev, level, fmt, arg...) \
|
|
|
- do { \
|
|
|
- if (dev->vfd->debug >= (level)) \
|
|
|
- printk(KERN_DEBUG "vivi: " fmt , ## arg); \
|
|
|
- } while (0)
|
|
|
+#define dprintk(dev, level, fmt, arg...) \
|
|
|
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
Basic structures
|
|
@@ -206,6 +218,7 @@ static LIST_HEAD(vivi_devlist);
|
|
|
|
|
|
struct vivi_dev {
|
|
|
struct list_head vivi_devlist;
|
|
|
+ struct v4l2_device v4l2_dev;
|
|
|
|
|
|
spinlock_t slock;
|
|
|
struct mutex mutex;
|
|
@@ -656,7 +669,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
|
|
|
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
|
|
|
|
|
|
if (IS_ERR(dma_q->kthread)) {
|
|
|
- printk(KERN_ERR "vivi: kernel_thread() failed\n");
|
|
|
+ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
|
|
|
return PTR_ERR(dma_q->kthread);
|
|
|
}
|
|
|
/* Wakes thread */
|
|
@@ -799,8 +812,12 @@ static struct videobuf_queue_ops vivi_video_qops = {
|
|
|
static int vidioc_querycap(struct file *file, void *priv,
|
|
|
struct v4l2_capability *cap)
|
|
|
{
|
|
|
+ struct vivi_fh *fh = priv;
|
|
|
+ struct vivi_dev *dev = fh->dev;
|
|
|
+
|
|
|
strcpy(cap->driver, "vivi");
|
|
|
strcpy(cap->card, "vivi");
|
|
|
+ strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
|
|
|
cap->version = VIVI_VERSION;
|
|
|
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
|
|
|
V4L2_CAP_STREAMING |
|
|
@@ -1124,32 +1141,21 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
|
|
|
|
|
|
static int vivi_open(struct file *file)
|
|
|
{
|
|
|
- int minor = video_devdata(file)->minor;
|
|
|
- struct vivi_dev *dev;
|
|
|
+ struct vivi_dev *dev = video_drvdata(file);
|
|
|
struct vivi_fh *fh = NULL;
|
|
|
int i;
|
|
|
int retval = 0;
|
|
|
|
|
|
- printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
|
|
|
-
|
|
|
- lock_kernel();
|
|
|
- list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
|
|
|
- if (dev->vfd->minor == minor)
|
|
|
- goto found;
|
|
|
- unlock_kernel();
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
-found:
|
|
|
mutex_lock(&dev->mutex);
|
|
|
dev->users++;
|
|
|
|
|
|
if (dev->users > 1) {
|
|
|
dev->users--;
|
|
|
- retval = -EBUSY;
|
|
|
- goto unlock;
|
|
|
+ mutex_unlock(&dev->mutex);
|
|
|
+ return -EBUSY;
|
|
|
}
|
|
|
|
|
|
- dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
|
|
|
+ dprintk(dev, 1, "open /dev/video%d type=%s users=%d\n", dev->vfd->num,
|
|
|
v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
|
|
|
|
|
|
/* allocate + initialize per filehandle data */
|
|
@@ -1157,14 +1163,11 @@ found:
|
|
|
if (NULL == fh) {
|
|
|
dev->users--;
|
|
|
retval = -ENOMEM;
|
|
|
- goto unlock;
|
|
|
}
|
|
|
-unlock:
|
|
|
mutex_unlock(&dev->mutex);
|
|
|
- if (retval) {
|
|
|
- unlock_kernel();
|
|
|
+
|
|
|
+ if (retval)
|
|
|
return retval;
|
|
|
- }
|
|
|
|
|
|
file->private_data = fh;
|
|
|
fh->dev = dev;
|
|
@@ -1193,7 +1196,6 @@ unlock:
|
|
|
sizeof(struct vivi_buffer), fh);
|
|
|
|
|
|
vivi_start_thread(fh);
|
|
|
- unlock_kernel();
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -1249,32 +1251,6 @@ static int vivi_close(struct file *file)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int vivi_release(void)
|
|
|
-{
|
|
|
- struct vivi_dev *dev;
|
|
|
- struct list_head *list;
|
|
|
-
|
|
|
- while (!list_empty(&vivi_devlist)) {
|
|
|
- list = vivi_devlist.next;
|
|
|
- list_del(list);
|
|
|
- dev = list_entry(list, struct vivi_dev, vivi_devlist);
|
|
|
-
|
|
|
- if (-1 != dev->vfd->minor) {
|
|
|
- printk(KERN_INFO "%s: unregistering /dev/video%d\n",
|
|
|
- VIVI_MODULE_NAME, dev->vfd->num);
|
|
|
- video_unregister_device(dev->vfd);
|
|
|
- } else {
|
|
|
- printk(KERN_INFO "%s: releasing /dev/video%d\n",
|
|
|
- VIVI_MODULE_NAME, dev->vfd->num);
|
|
|
- video_device_release(dev->vfd);
|
|
|
- }
|
|
|
-
|
|
|
- kfree(dev);
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
|
|
|
{
|
|
|
struct vivi_fh *fh = file->private_data;
|
|
@@ -1337,84 +1313,126 @@ static struct video_device vivi_template = {
|
|
|
.tvnorms = V4L2_STD_525_60,
|
|
|
.current_norm = V4L2_STD_NTSC_M,
|
|
|
};
|
|
|
+
|
|
|
/* -----------------------------------------------------------------
|
|
|
Initialization and module stuff
|
|
|
------------------------------------------------------------------*/
|
|
|
|
|
|
-/* This routine allocates from 1 to n_devs virtual drivers.
|
|
|
+static int vivi_release(void)
|
|
|
+{
|
|
|
+ struct vivi_dev *dev;
|
|
|
+ struct list_head *list;
|
|
|
|
|
|
- The real maximum number of virtual drivers will depend on how many drivers
|
|
|
- will succeed. This is limited to the maximum number of devices that
|
|
|
- videodev supports, which is equal to VIDEO_NUM_DEVICES.
|
|
|
- */
|
|
|
-static int __init vivi_init(void)
|
|
|
+ while (!list_empty(&vivi_devlist)) {
|
|
|
+ list = vivi_devlist.next;
|
|
|
+ list_del(list);
|
|
|
+ dev = list_entry(list, struct vivi_dev, vivi_devlist);
|
|
|
+
|
|
|
+ v4l2_info(&dev->v4l2_dev, "unregistering /dev/video%d\n",
|
|
|
+ dev->vfd->num);
|
|
|
+ video_unregister_device(dev->vfd);
|
|
|
+ v4l2_device_unregister(&dev->v4l2_dev);
|
|
|
+ kfree(dev);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __init vivi_create_instance(int i)
|
|
|
{
|
|
|
- int ret = -ENOMEM, i;
|
|
|
struct vivi_dev *dev;
|
|
|
struct video_device *vfd;
|
|
|
+ int ret;
|
|
|
|
|
|
- if (n_devs <= 0)
|
|
|
- n_devs = 1;
|
|
|
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
|
+ if (!dev)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- for (i = 0; i < n_devs; i++) {
|
|
|
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
|
- if (!dev)
|
|
|
- break;
|
|
|
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
|
|
|
+ "%s-%03d", VIVI_MODULE_NAME, i);
|
|
|
+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
|
|
|
+ if (ret)
|
|
|
+ goto free_dev;
|
|
|
|
|
|
- /* init video dma queues */
|
|
|
- INIT_LIST_HEAD(&dev->vidq.active);
|
|
|
- init_waitqueue_head(&dev->vidq.wq);
|
|
|
+ /* init video dma queues */
|
|
|
+ INIT_LIST_HEAD(&dev->vidq.active);
|
|
|
+ init_waitqueue_head(&dev->vidq.wq);
|
|
|
|
|
|
- /* initialize locks */
|
|
|
- spin_lock_init(&dev->slock);
|
|
|
- mutex_init(&dev->mutex);
|
|
|
+ /* initialize locks */
|
|
|
+ spin_lock_init(&dev->slock);
|
|
|
+ mutex_init(&dev->mutex);
|
|
|
|
|
|
- vfd = video_device_alloc();
|
|
|
- if (!vfd) {
|
|
|
- kfree(dev);
|
|
|
- break;
|
|
|
- }
|
|
|
+ ret = -ENOMEM;
|
|
|
+ vfd = video_device_alloc();
|
|
|
+ if (!vfd)
|
|
|
+ goto unreg_dev;
|
|
|
|
|
|
- *vfd = vivi_template;
|
|
|
+ *vfd = vivi_template;
|
|
|
|
|
|
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
|
|
|
- if (ret < 0) {
|
|
|
- video_device_release(vfd);
|
|
|
- kfree(dev);
|
|
|
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
|
|
|
+ if (ret < 0)
|
|
|
+ goto rel_vdev;
|
|
|
|
|
|
- /* If some registers succeeded, keep driver */
|
|
|
- if (i)
|
|
|
- ret = 0;
|
|
|
+ video_set_drvdata(vfd, dev);
|
|
|
|
|
|
- break;
|
|
|
- }
|
|
|
+ /* Now that everything is fine, let's add it to device list */
|
|
|
+ list_add_tail(&dev->vivi_devlist, &vivi_devlist);
|
|
|
|
|
|
- /* Now that everything is fine, let's add it to device list */
|
|
|
- list_add_tail(&dev->vivi_devlist, &vivi_devlist);
|
|
|
+ snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
|
|
|
+ vivi_template.name, vfd->num);
|
|
|
|
|
|
- snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
|
|
|
- vivi_template.name, vfd->minor);
|
|
|
+ if (video_nr >= 0)
|
|
|
+ video_nr++;
|
|
|
|
|
|
- if (video_nr >= 0)
|
|
|
- video_nr++;
|
|
|
+ dev->vfd = vfd;
|
|
|
+ v4l2_info(&dev->v4l2_dev, "V4L2 device registered as /dev/video%d\n",
|
|
|
+ vfd->num);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+rel_vdev:
|
|
|
+ video_device_release(vfd);
|
|
|
+unreg_dev:
|
|
|
+ v4l2_device_unregister(&dev->v4l2_dev);
|
|
|
+free_dev:
|
|
|
+ kfree(dev);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
- dev->vfd = vfd;
|
|
|
- printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
|
|
|
- VIVI_MODULE_NAME, vfd->num);
|
|
|
+/* This routine allocates from 1 to n_devs virtual drivers.
|
|
|
+
|
|
|
+ The real maximum number of virtual drivers will depend on how many drivers
|
|
|
+ will succeed. This is limited to the maximum number of devices that
|
|
|
+ videodev supports, which is equal to VIDEO_NUM_DEVICES.
|
|
|
+ */
|
|
|
+static int __init vivi_init(void)
|
|
|
+{
|
|
|
+ int ret, i;
|
|
|
+
|
|
|
+ if (n_devs <= 0)
|
|
|
+ n_devs = 1;
|
|
|
+
|
|
|
+ for (i = 0; i < n_devs; i++) {
|
|
|
+ ret = vivi_create_instance(i);
|
|
|
+ if (ret) {
|
|
|
+ /* If some instantiations succeeded, keep driver */
|
|
|
+ if (i)
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (ret < 0) {
|
|
|
- vivi_release();
|
|
|
printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
|
|
|
- } else {
|
|
|
- printk(KERN_INFO "Video Technology Magazine Virtual Video "
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ printk(KERN_INFO "Video Technology Magazine Virtual Video "
|
|
|
"Capture Board ver %u.%u.%u successfully loaded.\n",
|
|
|
(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
|
|
|
VIVI_VERSION & 0xFF);
|
|
|
|
|
|
- /* n_devs will reflect the actual number of allocated devices */
|
|
|
- n_devs = i;
|
|
|
- }
|
|
|
+ /* n_devs will reflect the actual number of allocated devices */
|
|
|
+ n_devs = i;
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1426,19 +1444,3 @@ static void __exit vivi_exit(void)
|
|
|
|
|
|
module_init(vivi_init);
|
|
|
module_exit(vivi_exit);
|
|
|
-
|
|
|
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
|
|
|
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
|
|
|
-MODULE_LICENSE("Dual BSD/GPL");
|
|
|
-
|
|
|
-module_param(video_nr, uint, 0444);
|
|
|
-MODULE_PARM_DESC(video_nr, "video iminor start number");
|
|
|
-
|
|
|
-module_param(n_devs, uint, 0444);
|
|
|
-MODULE_PARM_DESC(n_devs, "number of video devices to create");
|
|
|
-
|
|
|
-module_param_named(debug, vivi_template.debug, int, 0444);
|
|
|
-MODULE_PARM_DESC(debug, "activates debug info");
|
|
|
-
|
|
|
-module_param(vid_limit, int, 0644);
|
|
|
-MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
|