diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-10-04 13:36:54 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-12 13:37:16 +0200 |
commit | dd89601d47e2eeab7c17b25f2549444751bcffe4 (patch) | |
tree | da21e8b17e49d175f5b8cbd14a772bf00f7fb63a /drivers/media/video/v4l2-dev.c | |
parent | V4L/DVB (9132): cx18: Fix warning message for DMA done notification for inact... (diff) | |
download | linux-dd89601d47e2eeab7c17b25f2549444751bcffe4.tar.xz linux-dd89601d47e2eeab7c17b25f2549444751bcffe4.zip |
V4L/DVB (9133): v4l: disconnect kernel number from minor
The v4l core creates four different video devices (video, vbi, radio, vtx)
and each has its own range of minor numbers. However, modern devices keep
increasing the number of devices that they need so a maximum of 64 video
devices will not be enough in the future. In addition this scheme makes
it very hard to add new device types.
This patch disconnects the kernel number allocation (e.g. video0, video1,
etc.) from the actual minor number (just pick the first free minor).
This allows for much more flexibility in the future. However, it does
require the use of udev. For those who cannot use udev a new CONFIG option
was created that changes the allocation scheme back to the old behavior.
Thanks to Greg KH for suggesting this approach during the 2008 LPC.
In addition, several bugs were fixed in the ivtv and cx18 drivers: these
drivers try to allocate specific kernel numbers but that scheme contained
a bug which caused what should have been e.g. video17 to appear as e.g.
video2.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 96 |
1 files changed, 65 insertions, 31 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 7addf2fd55de..ccd6566a515e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c @@ -65,6 +65,7 @@ static struct device_attribute video_device_attrs[] = { */ static struct video_device *video_device[VIDEO_NUM_DEVICES]; static DEFINE_MUTEX(videodev_lock); +static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); struct video_device *video_device_alloc(void) { @@ -99,6 +100,7 @@ static void v4l2_chardev_release(struct kobject *kobj) /* Free up this device for reuse */ video_device[vfd->minor] = NULL; + clear_bit(vfd->num, video_nums[vfd->vfl_type]); mutex_unlock(&videodev_lock); /* Release the character device */ @@ -217,10 +219,10 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, int index) { int i = 0; - int base; - int end; int ret; - char *name_base; + int minor_offset = 0; + int minor_cnt = VIDEO_NUM_DEVICES; + const char *name_base; void *priv = video_get_drvdata(vfd); /* the release callback MUST be present */ @@ -231,23 +233,15 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, switch (type) { case VFL_TYPE_GRABBER: - base = MINOR_VFL_TYPE_GRABBER_MIN; - end = MINOR_VFL_TYPE_GRABBER_MAX+1; name_base = "video"; break; case VFL_TYPE_VTX: - base = MINOR_VFL_TYPE_VTX_MIN; - end = MINOR_VFL_TYPE_VTX_MAX+1; name_base = "vtx"; break; case VFL_TYPE_VBI: - base = MINOR_VFL_TYPE_VBI_MIN; - end = MINOR_VFL_TYPE_VBI_MAX+1; name_base = "vbi"; break; case VFL_TYPE_RADIO: - base = MINOR_VFL_TYPE_RADIO_MIN; - end = MINOR_VFL_TYPE_RADIO_MAX+1; name_base = "radio"; break; default: @@ -256,31 +250,70 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, return -EINVAL; } + vfd->vfl_type = type; + +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES + /* Keep the ranges for the first four types for historical + * reasons. + * Newer devices (not yet in place) should use the range + * of 128-191 and just pick the first free minor there + * (new style). */ + switch (type) { + case VFL_TYPE_GRABBER: + minor_offset = 0; + minor_cnt = 64; + break; + case VFL_TYPE_RADIO: + minor_offset = 64; + minor_cnt = 64; + break; + case VFL_TYPE_VTX: + minor_offset = 192; + minor_cnt = 32; + break; + case VFL_TYPE_VBI: + minor_offset = 224; + minor_cnt = 32; + break; + default: + minor_offset = 128; + minor_cnt = 64; + break; + } +#endif + /* Initialize the character device */ cdev_init(&vfd->cdev, vfd->fops); vfd->cdev.owner = vfd->fops->owner; /* pick a minor number */ mutex_lock(&videodev_lock); - if (nr >= 0 && nr < end-base) { - /* use the one the driver asked for */ - i = base + nr; - if (NULL != video_device[i]) { - mutex_unlock(&videodev_lock); - return -ENFILE; - } - } else { - /* use first free */ - for (i = base; i < end; i++) - if (NULL == video_device[i]) - break; - if (i == end) { - mutex_unlock(&videodev_lock); - return -ENFILE; - } + nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); + if (nr == minor_cnt) + nr = find_first_zero_bit(video_nums[type], minor_cnt); + if (nr == minor_cnt) { + printk(KERN_ERR "could not get a free kernel number\n"); + mutex_unlock(&videodev_lock); + return -ENFILE; } - video_device[i] = vfd; - vfd->vfl_type = type; - vfd->minor = i; +#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES + /* 1-on-1 mapping of kernel number to minor number */ + i = nr; +#else + /* The kernel number and minor numbers are independent */ + for (i = 0; i < VIDEO_NUM_DEVICES; i++) + if (video_device[i] == NULL) + break; + if (i == VIDEO_NUM_DEVICES) { + mutex_unlock(&videodev_lock); + printk(KERN_ERR "could not get a free minor\n"); + return -ENFILE; + } +#endif + vfd->minor = i + minor_offset; + vfd->num = nr; + set_bit(nr, video_nums[type]); + BUG_ON(video_device[vfd->minor]); + video_device[vfd->minor] = vfd; ret = get_index(vfd, index); vfd->index = ret; @@ -306,7 +339,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); if (vfd->parent) vfd->dev.parent = vfd->parent; - sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base); + sprintf(vfd->dev.bus_id, "%s%d", name_base, nr); ret = device_register(&vfd->dev); if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __func__); @@ -324,6 +357,7 @@ del_cdev: fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; + clear_bit(vfd->num, video_nums[type]); mutex_unlock(&videodev_lock); vfd->minor = -1; return ret; |