summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb/dvb-core
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2008-10-23 17:11:19 +0200
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-23 17:11:19 +0200
commit6b5f5ff6db5bdccf525c24c356d71bedfba91417 (patch)
tree6934f7ace5e65deeb962d4a6ac8e678c68eee623 /linux/drivers/media/dvb/dvb-core
parent4085bc31e472f8d6cabf91d541501f4577ca4e3b (diff)
downloadmediapointer-dvb-s2-6b5f5ff6db5bdccf525c24c356d71bedfba91417.tar.gz
mediapointer-dvb-s2-6b5f5ff6db5bdccf525c24c356d71bedfba91417.tar.bz2
Dynamic DVB minor allocation
From: Andreas Oberritter <obi@linuxtv.org> This is a multi-part message in MIME format. 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: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux/drivers/media/dvb/dvb-core')
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.c61
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvbdev.h1
2 files changed, 41 insertions, 21 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.c b/linux/drivers/media/dvb/dvb-core/dvbdev.c
index c2e824710..a35286f1a 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.c
@@ -51,33 +51,27 @@ static const char * const dnames[] = {
"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 nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
+#endif
static struct class *dvb_class;
-static struct dvb_device* dvbdev_find_device (int minor)
-{
- 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 struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
lock_kernel();
- dvbdev = dvbdev_find_device (iminor(inode));
+ down_read(&minor_rwsem);
+ dvbdev = dvb_minors[iminor(inode)];
if (dvbdev && dvbdev->fops) {
int err = 0;
@@ -97,9 +91,11 @@ static int dvb_device_open(struct inode *inode, struct file *file)
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
+ up_read(&minor_rwsem);
unlock_kernel();
return err;
}
+ up_read(&minor_rwsem);
unlock_kernel();
return -ENODEV;
}
@@ -201,6 +197,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
#else
struct class_device *clsdev;
#endif
+ int minor;
int id;
mutex_lock(&dvbdev_register_lock);
@@ -240,6 +237,26 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
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);
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
@@ -248,11 +265,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
#elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 27)
clsdev = device_create_drvdata(dvb_class, adap->device,
- MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+ MKDEV(DVB_MAJOR, minor),
NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
#else
clsdev = device_create(dvb_class, adap->device,
- MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+ MKDEV(DVB_MAJOR, minor),
"dvb%d.%s%d", adap->num, dnames[type], id);
#endif
if (IS_ERR(clsdev)) {
@@ -262,8 +279,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",
- adap->num, dnames[type], id, nums2minor(adap->num, type, id),
- nums2minor(adap->num, type, id));
+ adap->num, dnames[type], id, minor, minor);
return 0;
}
@@ -275,8 +291,11 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
- device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
- dvbdev->type, dvbdev->id)));
+ down_write(&minor_rwsem);
+ dvb_minors[dvbdev->minor] = NULL;
+ up_write(&minor_rwsem);
+
+ device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
list_del (&dvbdev->list_head);
kfree (dvbdev->fops);
diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h
index 574e336ba..dca49cf96 100644
--- a/linux/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h
@@ -74,6 +74,7 @@ struct dvb_device {
struct file_operations *fops;
struct dvb_adapter *adapter;
int type;
+ int minor;
u32 id;
/* in theory, 'users' can vanish now,