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

Commit b566762a authored by Takashi Iwai's avatar Takashi Iwai
Browse files

Merge branch 'topic/seq-autoload' into for-next

parents e2009536 d5129f33
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -108,9 +108,13 @@ int snd_seq_event_port_detach(int client, int port);
#ifdef CONFIG_MODULES
void snd_seq_autoload_lock(void);
void snd_seq_autoload_unlock(void);
void snd_seq_autoload_init(void);
#define snd_seq_autoload_exit()	snd_seq_autoload_lock()
#else
#define snd_seq_autoload_lock()
#define snd_seq_autoload_unlock()
#define snd_seq_autoload_init()
#define snd_seq_autoload_exit()
#endif

#endif /* __SOUND_SEQ_KERNEL_H */
+3 −2
Original line number Diff line number Diff line
@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void)
{
	int err;

	snd_seq_autoload_lock();
	if ((err = client_init_data()) < 0)
		goto error;

@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void)
	if ((err = snd_seq_system_client_init()) < 0)
		goto error;

	snd_seq_autoload_init();
 error:
	snd_seq_autoload_unlock();
	return err;
}

@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void)

	/* release event memory */
	snd_sequencer_memory_done();

	snd_seq_autoload_exit();
}

module_init(alsa_seq_init)
+72 −31
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
#define DRIVER_LOADED		(1<<0)
#define DRIVER_REQUESTED	(1<<1)
#define DRIVER_LOCKED		(1<<2)
#define DRIVER_REQUESTING	(1<<3)

struct ops_list {
	char id[ID_LEN];	/* driver id */
@@ -127,32 +128,26 @@ static void snd_seq_device_info(struct snd_info_entry *entry,

#ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */
static int snd_seq_in_init;
static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
void snd_seq_autoload_lock(void)
{
	snd_seq_in_init++;
	atomic_inc(&snd_seq_in_init);
}

void snd_seq_autoload_unlock(void)
{
	snd_seq_in_init--;
	atomic_dec(&snd_seq_in_init);
}
#endif

void snd_seq_device_load_drivers(void)
static void autoload_drivers(void)
{
#ifdef CONFIG_MODULES
	/* avoid reentrance */
	if (atomic_inc_return(&snd_seq_in_init) == 1) {
		struct ops_list *ops;

	/* Calling request_module during module_init()
	 * may cause blocking.
	 */
	if (snd_seq_in_init)
		return;

		mutex_lock(&ops_mutex);
		list_for_each_entry(ops, &opslist, list) {
		if (! (ops->driver & DRIVER_LOADED) &&
			if ((ops->driver & DRIVER_REQUESTING) &&
			    !(ops->driver & DRIVER_REQUESTED)) {
				ops->used++;
				mutex_unlock(&ops_mutex);
@@ -163,6 +158,52 @@ void snd_seq_device_load_drivers(void)
			}
		}
		mutex_unlock(&ops_mutex);
	}
	atomic_dec(&snd_seq_in_init);
}

static void call_autoload(struct work_struct *work)
{
	autoload_drivers();
}

static DECLARE_WORK(autoload_work, call_autoload);

static void try_autoload(struct ops_list *ops)
{
	if (!ops->driver) {
		ops->driver |= DRIVER_REQUESTING;
		schedule_work(&autoload_work);
	}
}

static void queue_autoload_drivers(void)
{
	struct ops_list *ops;

	mutex_lock(&ops_mutex);
	list_for_each_entry(ops, &opslist, list)
		try_autoload(ops);
	mutex_unlock(&ops_mutex);
}

void snd_seq_autoload_init(void)
{
	atomic_dec(&snd_seq_in_init);
#ifdef CONFIG_SND_SEQUENCER_MODULE
	/* initial autoload only when snd-seq is a module */
	queue_autoload_drivers();
#endif
}
#else
#define try_autoload(ops) /* NOP */
#endif

void snd_seq_device_load_drivers(void)
{
#ifdef CONFIG_MODULES
	queue_autoload_drivers();
	flush_work(&autoload_work);
#endif
}

@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
	ops->num_devices++;
	mutex_unlock(&ops->reg_mutex);

	unlock_driver(ops);
	
	if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
		snd_seq_device_free(dev);
		return err;
	}
	
	try_autoload(ops);
	unlock_driver(ops);

	if (result)
		*result = dev;

@@ -318,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
	    entry->init_device == NULL || entry->free_device == NULL)
		return -EINVAL;

	snd_seq_autoload_lock();
	ops = find_driver(id, 1);
	if (ops == NULL) {
		snd_seq_autoload_unlock();
	if (ops == NULL)
		return -ENOMEM;
	}
	if (ops->driver & DRIVER_LOADED) {
		pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
		unlock_driver(ops);
		snd_seq_autoload_unlock();
		return -EBUSY;
	}

@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
	mutex_unlock(&ops->reg_mutex);

	unlock_driver(ops);
	snd_seq_autoload_unlock();

	return 0;
}
@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void)

static void __exit alsa_seq_device_exit(void)
{
#ifdef CONFIG_MODULES
	cancel_work_sync(&autoload_work);
#endif
	remove_drivers();
#ifdef CONFIG_PROC_FS
	snd_info_free_entry(info_entry);
@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES
EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif