Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3827119e authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/soundcore-preclaim' into for-linus

* topic/soundcore-preclaim:
  sound: make OSS device number claiming optional and schedule its removal
  sound: request char-major-* module aliases for missing OSS devices
  chrdev: implement __[un]register_chrdev()
parents 9d416811 93fe4483
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -468,3 +468,27 @@ Why: cpu_policy_rwsem has a new cleaner definition making it local to
	cpufreq core and contained inside cpufreq.c. Other dependent
	drivers should not use it in order to safely avoid lockdep issues.
Who:	Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>

----------------------------

What:	sound-slot/service-* module aliases and related clutters in
	sound/sound_core.c
When:	August 2010
Why:	OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR
	(14) and requests modules using custom sound-slot/service-*
	module aliases.  The only benefit of doing this is allowing
	use of custom module aliases which might as well be considered
	a bug at this point.  This preemptive claiming prevents
	alternative OSS implementations.

	Till the feature is removed, the kernel will be requesting
	both sound-slot/service-* and the standard char-major-* module
	aliases and allow turning off the pre-claiming selectively via
	CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss
	kernel parameter.

	After the transition phase is complete, both the custom module
	aliases and switches to disable it will go away.  This removal
	will also allow making ALSA OSS emulation independent of
	sound_core.  The dependency will be broken then too.
Who:	Tejun Heo <tj@kernel.org>
+26 −13
Original line number Diff line number Diff line
@@ -237,8 +237,10 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
}

/**
 * register_chrdev() - Register a major number for character devices.
 * __register_chrdev() - create and register a cdev occupying a range of minors
 * @major: major device number or 0 for dynamic allocation
 * @baseminor: first of the requested range of minor numbers
 * @count: the number of minor numbers required
 * @name: name of this range of devices
 * @fops: file operations associated with this devices
 *
@@ -254,11 +256,9 @@ int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
 * /dev. It only helps to keep track of the different owners of devices. If
 * your module name has only one type of devices it's ok to use e.g. the name
 * of the module here.
 *
 * This function registers a range of 256 minor numbers. The first minor number
 * is 0.
 */
int register_chrdev(unsigned int major, const char *name,
int __register_chrdev(unsigned int major, unsigned int baseminor,
		      unsigned int count, const char *name,
		      const struct file_operations *fops)
{
	struct char_device_struct *cd;
@@ -266,7 +266,7 @@ int register_chrdev(unsigned int major, const char *name,
	char *s;
	int err = -ENOMEM;

	cd = __register_chrdev_region(major, 0, 256, name);
	cd = __register_chrdev_region(major, baseminor, count, name);
	if (IS_ERR(cd))
		return PTR_ERR(cd);
	
@@ -280,7 +280,7 @@ int register_chrdev(unsigned int major, const char *name,
	for (s = strchr(kobject_name(&cdev->kobj),'/'); s; s = strchr(s, '/'))
		*s = '!';
		
	err = cdev_add(cdev, MKDEV(cd->major, 0), 256);
	err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);
	if (err)
		goto out;

@@ -290,7 +290,7 @@ int register_chrdev(unsigned int major, const char *name,
out:
	kobject_put(&cdev->kobj);
out2:
	kfree(__unregister_chrdev_region(cd->major, 0, 256));
	kfree(__unregister_chrdev_region(cd->major, baseminor, count));
	return err;
}

@@ -316,10 +316,23 @@ void unregister_chrdev_region(dev_t from, unsigned count)
	}
}

void unregister_chrdev(unsigned int major, const char *name)
/**
 * __unregister_chrdev - unregister and destroy a cdev
 * @major: major device number
 * @baseminor: first of the range of minor numbers
 * @count: the number of minor numbers this cdev is occupying
 * @name: name of this range of devices
 *
 * Unregister and destroy the cdev occupying the region described by
 * @major, @baseminor and @count.  This function undoes what
 * __register_chrdev() did.
 */
void __unregister_chrdev(unsigned int major, unsigned int baseminor,
			 unsigned int count, const char *name)
{
	struct char_device_struct *cd;
	cd = __unregister_chrdev_region(major, 0, 256);

	cd = __unregister_chrdev_region(major, baseminor, count);
	if (cd && cd->cdev)
		cdev_del(cd->cdev);
	kfree(cd);
@@ -568,6 +581,6 @@ EXPORT_SYMBOL(cdev_alloc);
EXPORT_SYMBOL(cdev_del);
EXPORT_SYMBOL(cdev_add);
EXPORT_SYMBOL(cdev_index);
EXPORT_SYMBOL(register_chrdev);
EXPORT_SYMBOL(unregister_chrdev);
EXPORT_SYMBOL(__register_chrdev);
EXPORT_SYMBOL(__unregister_chrdev);
EXPORT_SYMBOL(directly_mappable_cdev_bdi);
+16 −3
Original line number Diff line number Diff line
@@ -1998,12 +1998,25 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *);
#define CHRDEV_MAJOR_HASH_SIZE	255
extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
extern int register_chrdev_region(dev_t, unsigned, const char *);
extern int register_chrdev(unsigned int, const char *,
			   const struct file_operations *);
extern void unregister_chrdev(unsigned int, const char *);
extern int __register_chrdev(unsigned int major, unsigned int baseminor,
			     unsigned int count, const char *name,
			     const struct file_operations *fops);
extern void __unregister_chrdev(unsigned int major, unsigned int baseminor,
				unsigned int count, const char *name);
extern void unregister_chrdev_region(dev_t, unsigned);
extern void chrdev_show(struct seq_file *,off_t);

static inline int register_chrdev(unsigned int major, const char *name,
				  const struct file_operations *fops)
{
	return __register_chrdev(major, 0, 256, name, fops);
}

static inline void unregister_chrdev(unsigned int major, const char *name)
{
	__unregister_chrdev(major, 0, 256, name);
}

/* fs/block_dev.c */
#define BDEVNAME_SIZE	32	/* Largest string for a blockdev identifier */
#define BDEVT_SIZE	10	/* Largest string for MAJ:MIN for blkdev */
+28 −0
Original line number Diff line number Diff line
@@ -32,6 +32,34 @@ config SOUND_OSS_CORE
	bool
	default n

config SOUND_OSS_CORE_PRECLAIM
	bool "Preclaim OSS device numbers"
	depends on SOUND_OSS_CORE
	default y
	help
	  With this option enabled, the kernel will claim all OSS device
	  numbers if any OSS support (native or emulation) is enabled
	  whether the respective module is loaded or not and try to load the
	  appropriate module using sound-slot/service-* and char-major-*
	  module aliases when one of the device numbers is opened.  With
	  this option disabled, kernel will only claim actually in-use
	  device numbers and opening a missing device will generate only the
	  standard char-major-* aliases.

	  The only visible difference is use of additional module aliases
	  and whether OSS sound devices appear multiple times in
	  /proc/devices.  sound-slot/service-* module aliases are scheduled
	  to be removed (ie. PRECLAIM won't be available) and this option is
	  to make the transition easier.  This option can be overridden
	  during boot using the kernel parameter soundcore.preclaim_oss.

	  Disabling this allows alternative OSS implementations.

	  Please read Documentation/feature-removal-schedule.txt for
	  details.

	  If unusre, say Y.

source "sound/oss/dmasound/Kconfig"

if !M68K
+82 −18
Original line number Diff line number Diff line
@@ -127,6 +127,46 @@ extern int msnd_classic_init(void);
extern int msnd_pinnacle_init(void);
#endif

/*
 * By default, OSS sound_core claims full legacy minor range (0-255)
 * of SOUND_MAJOR to trap open attempts to any sound minor and
 * requests modules using custom sound-slot/service-* module aliases.
 * The only benefit of doing this is allowing use of custom module
 * aliases instead of the standard char-major-* ones.  This behavior
 * prevents alternative OSS implementation and is scheduled to be
 * removed.
 *
 * CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel
 * parameter are added to allow distros and developers to try and
 * switch to alternative implementations without needing to rebuild
 * the kernel in the meantime.  If preclaim_oss is non-zero, the
 * kernel will behave the same as before.  All SOUND_MAJOR minors are
 * preclaimed and the custom module aliases along with standard chrdev
 * ones are emitted if a missing device is opened.  If preclaim_oss is
 * zero, sound_core only grabs what's actually in use and for missing
 * devices only the standard chrdev aliases are requested.
 *
 * All these clutters are scheduled to be removed along with
 * sound-slot/service-* module aliases.  Please take a look at
 * feature-removal-schedule.txt for details.
 */
#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM
static int preclaim_oss = 1;
#else
static int preclaim_oss = 0;
#endif

module_param(preclaim_oss, int, 0444);

static int soundcore_open(struct inode *, struct file *);

static const struct file_operations soundcore_fops =
{
	/* We must have an owner or the module locking fails */
	.owner	= THIS_MODULE,
	.open	= soundcore_open,
};

/*
 *	Low level list operator. Scan the ordered list, find a hole and
 *	join into it. Called with the lock asserted
@@ -221,6 +261,7 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
		return -ENOMEM;

	spin_lock(&sound_loader_lock);
retry:
	r = __sound_insert_unit(s, list, fops, index, low, top);
	spin_unlock(&sound_loader_lock);
	
@@ -231,9 +272,29 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati
	else
		sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);

	if (!preclaim_oss) {
		/*
		 * Something else might have grabbed the minor.  If
		 * first free slot is requested, rescan with @low set
		 * to the next unit; otherwise, -EBUSY.
		 */
		r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name,
				      &soundcore_fops);
		if (r < 0) {
			spin_lock(&sound_loader_lock);
			__sound_remove_unit(list, s->unit_minor);
			if (index < 0) {
				low = s->unit_minor + SOUND_STEP;
				goto retry;
			}
			spin_unlock(&sound_loader_lock);
			return -EBUSY;
		}
	}

	device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor),
		      NULL, s->name+6);
	return r;
	return s->unit_minor;

fail:
	kfree(s);
@@ -254,6 +315,9 @@ static void sound_remove_unit(struct sound_unit **list, int unit)
	p = __sound_remove_unit(list, unit);
	spin_unlock(&sound_loader_lock);
	if (p) {
		if (!preclaim_oss)
			__unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1,
					    p->name);
		device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor));
		kfree(p);
	}
@@ -491,19 +555,6 @@ void unregister_sound_dsp(int unit)

EXPORT_SYMBOL(unregister_sound_dsp);

/*
 *	Now our file operations
 */

static int soundcore_open(struct inode *, struct file *);

static const struct file_operations soundcore_fops=
{
	/* We must have an owner or the module locking fails */
	.owner	= THIS_MODULE,
	.open	= soundcore_open,
};

static struct sound_unit *__look_for_unit(int chain, int unit)
{
	struct sound_unit *s;
@@ -539,8 +590,9 @@ static int soundcore_open(struct inode *inode, struct file *file)
	s = __look_for_unit(chain, unit);
	if (s)
		new_fops = fops_get(s->unit_fops);
	if (!new_fops) {
	if (preclaim_oss && !new_fops) {
		spin_unlock(&sound_loader_lock);

		/*
		 *  Please, don't change this order or code.
		 *  For ALSA slot means soundcard and OSS emulation code
@@ -550,6 +602,17 @@ static int soundcore_open(struct inode *inode, struct file *file)
		 */
		request_module("sound-slot-%i", unit>>4);
		request_module("sound-service-%i-%i", unit>>4, chain);

		/*
		 * sound-slot/service-* module aliases are scheduled
		 * for removal in favor of the standard char-major-*
		 * module aliases.  For the time being, generate both
		 * the legacy and standard module aliases to ease
		 * transition.
		 */
		if (request_module("char-major-%d-%d", SOUND_MAJOR, unit) > 0)
			request_module("char-major-%d", SOUND_MAJOR);

		spin_lock(&sound_loader_lock);
		s = __look_for_unit(chain, unit);
		if (s)
@@ -593,7 +656,8 @@ static void cleanup_oss_soundcore(void)

static int __init init_oss_soundcore(void)
{
	if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) {
	if (preclaim_oss &&
	    register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
		printk(KERN_ERR "soundcore: sound device already in use.\n");
		return -EBUSY;
	}