Commit 5dd3f307 authored by Andreas Oberritter's avatar Andreas Oberritter Committed by Mauro Carvalho Chehab

V4L/DVB (9361): Dynamic DVB minor allocation

Implement dynamic minor allocation for DVB, to allow more than four
devices of the same type per adapter, based on drivers/usb/core/file.c.

Add a new config option, DVB_DYNAMIC_MINORS, to make use of this
feature, which defaults to no for backwards compatibility.
Signed-off-by: default avatarAndreas Oberritter <obi@linuxtv.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 568e9bb8
...@@ -2,6 +2,19 @@ ...@@ -2,6 +2,19 @@
# DVB device configuration # DVB device configuration
# #
config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation"
depends on DVB_CORE
default n
help
If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number.
This means that you can have more than 4 of a single type
of device (like demuxes and frontends) per adapter, but udev
will be required to manage the device nodes.
If you are unsure about this, say N here.
menuconfig DVB_CAPTURE_DRIVERS menuconfig DVB_CAPTURE_DRIVERS
bool "DVB/ATSC adapters" bool "DVB/ATSC adapters"
depends on DVB_CORE depends on DVB_CORE
......
...@@ -50,33 +50,27 @@ static const char * const dnames[] = { ...@@ -50,33 +50,27 @@ static const char * const dnames[] = {
"net", "osd" "net", "osd"
}; };
#ifdef CONFIG_DVB_DYNAMIC_MINORS
#define MAX_DVB_MINORS 256
#define DVB_MAX_IDS MAX_DVB_MINORS
#else
#define DVB_MAX_IDS 4 #define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
#endif
static struct class *dvb_class; static struct class *dvb_class;
static struct dvb_device* dvbdev_find_device (int minor) static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
{ static DECLARE_RWSEM(minor_rwsem);
struct dvb_adapter *adap;
list_for_each_entry(adap, &dvb_adapter_list, list_head) {
struct dvb_device *dev;
list_for_each_entry(dev, &adap->device_list, list_head)
if (nums2minor(adap->num, dev->type, dev->id) == minor)
return dev;
}
return NULL;
}
static int dvb_device_open(struct inode *inode, struct file *file) static int dvb_device_open(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
lock_kernel(); lock_kernel();
dvbdev = dvbdev_find_device (iminor(inode)); down_read(&minor_rwsem);
dvbdev = dvb_minors[iminor(inode)];
if (dvbdev && dvbdev->fops) { if (dvbdev && dvbdev->fops) {
int err = 0; int err = 0;
...@@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file) ...@@ -92,9 +86,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
file->f_op = fops_get(old_fops); file->f_op = fops_get(old_fops);
} }
fops_put(old_fops); fops_put(old_fops);
up_read(&minor_rwsem);
unlock_kernel(); unlock_kernel();
return err; return err;
} }
up_read(&minor_rwsem);
unlock_kernel(); unlock_kernel();
return -ENODEV; return -ENODEV;
} }
...@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct file_operations *dvbdevfops; struct file_operations *dvbdevfops;
struct device *clsdev; struct device *clsdev;
int minor;
int id; int id;
mutex_lock(&dvbdev_register_lock); mutex_lock(&dvbdev_register_lock);
...@@ -231,6 +228,26 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -231,6 +228,26 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
list_add_tail (&dvbdev->list_head, &adap->device_list); list_add_tail (&dvbdev->list_head, &adap->device_list);
down_write(&minor_rwsem);
#ifdef CONFIG_DVB_DYNAMIC_MINORS
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (dvb_minors[minor] == NULL)
break;
if (minor == MAX_DVB_MINORS) {
kfree(dvbdevfops);
kfree(dvbdev);
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
#else
minor = nums2minor(adap->num, type, id);
#endif
dvbdev->minor = minor;
dvb_minors[minor] = dvbdev;
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
clsdev = device_create(dvb_class, adap->device, clsdev = device_create(dvb_class, adap->device,
...@@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ...@@ -243,8 +260,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
} }
dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id), adap->num, dnames[type], id, minor, minor);
nums2minor(adap->num, type, id));
return 0; return 0;
} }
...@@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev) ...@@ -256,8 +272,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev) if (!dvbdev)
return; return;
device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, down_write(&minor_rwsem);
dvbdev->type, dvbdev->id))); dvb_minors[dvbdev->minor] = NULL;
up_write(&minor_rwsem);
device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head); list_del (&dvbdev->list_head);
kfree (dvbdev->fops); kfree (dvbdev->fops);
......
...@@ -74,6 +74,7 @@ struct dvb_device { ...@@ -74,6 +74,7 @@ struct dvb_device {
struct file_operations *fops; struct file_operations *fops;
struct dvb_adapter *adapter; struct dvb_adapter *adapter;
int type; int type;
int minor;
u32 id; u32 id;
/* in theory, 'users' can vanish now, /* in theory, 'users' can vanish now,
......
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