Commit 5ab6c9af authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (10645): vivi: introduce v4l2_device and do several cleanups

- add v4l2_device
- remove BKL
- make the debug parameter settable on the fly
- set bus_info in querycap
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b0167600
...@@ -33,12 +33,13 @@ ...@@ -33,12 +33,13 @@
#include <linux/videodev.h> #include <linux/videodev.h>
#endif #endif
#include <linux/interrupt.h> #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/kthread.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/freezer.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" #define VIVI_MODULE_NAME "vivi"
...@@ -47,18 +48,32 @@ ...@@ -47,18 +48,32 @@
#define WAKE_DENOMINATOR 1001 #define WAKE_DENOMINATOR 1001
#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
#include "font.h"
#define VIVI_MAJOR_VERSION 0 #define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 5 #define VIVI_MINOR_VERSION 6
#define VIVI_RELEASE 0 #define VIVI_RELEASE 0
#define VIVI_VERSION \ #define VIVI_VERSION \
KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
/* Declare static vars that will be used as parameters */ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */ MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */ MODULE_LICENSE("Dual BSD/GPL");
static int n_devs = 1; /* Number of virtual devices */
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 */ /* supported controls */
static struct v4l2_queryctrl vivi_qctrl[] = { static struct v4l2_queryctrl vivi_qctrl[] = {
...@@ -112,11 +127,8 @@ static struct v4l2_queryctrl vivi_qctrl[] = { ...@@ -112,11 +127,8 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
static int qctl_regs[ARRAY_SIZE(vivi_qctrl)]; static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
#define dprintk(dev, level, fmt, arg...) \ #define dprintk(dev, level, fmt, arg...) \
do { \ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
if (dev->vfd->debug >= (level)) \
printk(KERN_DEBUG "vivi: " fmt , ## arg); \
} while (0)
/* ------------------------------------------------------------------ /* ------------------------------------------------------------------
Basic structures Basic structures
...@@ -206,6 +218,7 @@ static LIST_HEAD(vivi_devlist); ...@@ -206,6 +218,7 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev { struct vivi_dev {
struct list_head vivi_devlist; struct list_head vivi_devlist;
struct v4l2_device v4l2_dev;
spinlock_t slock; spinlock_t slock;
struct mutex mutex; struct mutex mutex;
...@@ -656,7 +669,7 @@ static int vivi_start_thread(struct vivi_fh *fh) ...@@ -656,7 +669,7 @@ static int vivi_start_thread(struct vivi_fh *fh)
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
if (IS_ERR(dma_q->kthread)) { 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); return PTR_ERR(dma_q->kthread);
} }
/* Wakes thread */ /* Wakes thread */
...@@ -799,8 +812,12 @@ static struct videobuf_queue_ops vivi_video_qops = { ...@@ -799,8 +812,12 @@ static struct videobuf_queue_ops vivi_video_qops = {
static int vidioc_querycap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap) struct v4l2_capability *cap)
{ {
struct vivi_fh *fh = priv;
struct vivi_dev *dev = fh->dev;
strcpy(cap->driver, "vivi"); strcpy(cap->driver, "vivi");
strcpy(cap->card, "vivi"); strcpy(cap->card, "vivi");
strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
cap->version = VIVI_VERSION; cap->version = VIVI_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING | V4L2_CAP_STREAMING |
...@@ -1124,32 +1141,21 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -1124,32 +1141,21 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static int vivi_open(struct file *file) static int vivi_open(struct file *file)
{ {
int minor = video_devdata(file)->minor; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev;
struct vivi_fh *fh = NULL; struct vivi_fh *fh = NULL;
int i; int i;
int retval = 0; 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); mutex_lock(&dev->mutex);
dev->users++; dev->users++;
if (dev->users > 1) { if (dev->users > 1) {
dev->users--; dev->users--;
retval = -EBUSY; mutex_unlock(&dev->mutex);
goto unlock; 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); v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
/* allocate + initialize per filehandle data */ /* allocate + initialize per filehandle data */
...@@ -1157,14 +1163,11 @@ static int vivi_open(struct file *file) ...@@ -1157,14 +1163,11 @@ static int vivi_open(struct file *file)
if (NULL == fh) { if (NULL == fh) {
dev->users--; dev->users--;
retval = -ENOMEM; retval = -ENOMEM;
goto unlock;
} }
unlock:
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
if (retval) {
unlock_kernel(); if (retval)
return retval; return retval;
}
file->private_data = fh; file->private_data = fh;
fh->dev = dev; fh->dev = dev;
...@@ -1193,7 +1196,6 @@ static int vivi_open(struct file *file) ...@@ -1193,7 +1196,6 @@ static int vivi_open(struct file *file)
sizeof(struct vivi_buffer), fh); sizeof(struct vivi_buffer), fh);
vivi_start_thread(fh); vivi_start_thread(fh);
unlock_kernel();
return 0; return 0;
} }
...@@ -1249,32 +1251,6 @@ static int vivi_close(struct file *file) ...@@ -1249,32 +1251,6 @@ static int vivi_close(struct file *file)
return 0; 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) static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct vivi_fh *fh = file->private_data; struct vivi_fh *fh = file->private_data;
...@@ -1337,84 +1313,126 @@ static struct video_device vivi_template = { ...@@ -1337,84 +1313,126 @@ static struct video_device vivi_template = {
.tvnorms = V4L2_STD_525_60, .tvnorms = V4L2_STD_525_60,
.current_norm = V4L2_STD_NTSC_M, .current_norm = V4L2_STD_NTSC_M,
}; };
/* ----------------------------------------------------------------- /* -----------------------------------------------------------------
Initialization and module stuff 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 while (!list_empty(&vivi_devlist)) {
will succeed. This is limited to the maximum number of devices that list = vivi_devlist.next;
videodev supports, which is equal to VIDEO_NUM_DEVICES. list_del(list);
*/ dev = list_entry(list, struct vivi_dev, vivi_devlist);
static int __init vivi_init(void)
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 vivi_dev *dev;
struct video_device *vfd; struct video_device *vfd;
int ret;
if (n_devs <= 0) dev = kzalloc(sizeof(*dev), GFP_KERNEL);
n_devs = 1; if (!dev)
return -ENOMEM;
for (i = 0; i < n_devs; i++) { snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
dev = kzalloc(sizeof(*dev), GFP_KERNEL); "%s-%03d", VIVI_MODULE_NAME, i);
if (!dev) ret = v4l2_device_register(NULL, &dev->v4l2_dev);
break; if (ret)
goto free_dev;
/* init video dma queues */ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq); init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */ /* initialize locks */
spin_lock_init(&dev->slock); spin_lock_init(&dev->slock);
mutex_init(&dev->mutex); mutex_init(&dev->mutex);
vfd = video_device_alloc(); ret = -ENOMEM;
if (!vfd) { vfd = video_device_alloc();
kfree(dev); if (!vfd)
break; goto unreg_dev;
}
*vfd = vivi_template; *vfd = vivi_template;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0) { if (ret < 0)
video_device_release(vfd); goto rel_vdev;
kfree(dev);
/* If some registers succeeded, keep driver */ video_set_drvdata(vfd, dev);
if (i)
ret = 0;
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 */ snprintf(vfd->name, sizeof(vfd->name), "%s (%i)",
list_add_tail(&dev->vivi_devlist, &vivi_devlist); vivi_template.name, vfd->num);
snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", if (video_nr >= 0)
vivi_template.name, vfd->minor); video_nr++;
if (video_nr >= 0) dev->vfd = vfd;
video_nr++; 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; /* This routine allocates from 1 to n_devs virtual drivers.
printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
VIVI_MODULE_NAME, vfd->num); 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) { if (ret < 0) {
vivi_release();
printk(KERN_INFO "Error %d while loading vivi driver\n", ret); printk(KERN_INFO "Error %d while loading vivi driver\n", ret);
} else { return ret;
printk(KERN_INFO "Video Technology Magazine Virtual Video " }
printk(KERN_INFO "Video Technology Magazine Virtual Video "
"Capture Board ver %u.%u.%u successfully loaded.\n", "Capture Board ver %u.%u.%u successfully loaded.\n",
(VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF,
VIVI_VERSION & 0xFF); VIVI_VERSION & 0xFF);
/* n_devs will reflect the actual number of allocated devices */ /* n_devs will reflect the actual number of allocated devices */
n_devs = i; n_devs = i;
}
return ret; return ret;
} }
...@@ -1426,19 +1444,3 @@ static void __exit vivi_exit(void) ...@@ -1426,19 +1444,3 @@ static void __exit vivi_exit(void)
module_init(vivi_init); module_init(vivi_init);
module_exit(vivi_exit); 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");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment