aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/dvb/dvb-core/dvbdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/dvb-core/dvbdev.c')
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c71
1 files changed, 50 insertions, 21 deletions
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a113744a56c..6c571d9f011 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -50,33 +50,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;
@@ -92,9 +86,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;
}
@@ -192,6 +188,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct device *clsdev;
+ int minor;
int id;
mutex_lock(&dvbdev_register_lock);
@@ -231,11 +228,31 @@ 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);
clsdev = device_create(dvb_class, adap->device,
- MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+ MKDEV(DVB_MAJOR, minor),
+ dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
__func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
@@ -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",
- adap->num, dnames[type], id, nums2minor(adap->num, type, id),
- nums2minor(adap->num, type, id));
+ adap->num, dnames[type], id, minor, minor);
return 0;
}
@@ -256,8 +272,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);
@@ -413,6 +432,15 @@ out:
return err;
}
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+ add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+ add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+ return 0;
+}
+
static int __init init_dvbdev(void)
{
int retval;
@@ -434,6 +462,7 @@ static int __init init_dvbdev(void)
retval = PTR_ERR(dvb_class);
goto error;
}
+ dvb_class->dev_uevent = dvb_uevent;
return 0;
error: