# 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
bool "DVB/ATSC adapters"
depends on DVB_CORE
"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;
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;
}
struct dvb_device *dvbdev;
struct file_operations *dvbdevfops;
struct device *clsdev;
+ int minor;
int id;
mutex_lock(&dvbdev_register_lock);
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,
}
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;
}
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);