Merge branch 'topic/seq-autoload' into for-next
This commit is contained in:
Коммит
b566762a67
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,42 +128,82 @@ 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);
|
||||
}
|
||||
|
||||
static void autoload_drivers(void)
|
||||
{
|
||||
/* avoid reentrance */
|
||||
if (atomic_inc_return(&snd_seq_in_init) == 1) {
|
||||
struct ops_list *ops;
|
||||
|
||||
mutex_lock(&ops_mutex);
|
||||
list_for_each_entry(ops, &opslist, list) {
|
||||
if ((ops->driver & DRIVER_REQUESTING) &&
|
||||
!(ops->driver & DRIVER_REQUESTED)) {
|
||||
ops->used++;
|
||||
mutex_unlock(&ops_mutex);
|
||||
ops->driver |= DRIVER_REQUESTED;
|
||||
request_module("snd-%s", ops->id);
|
||||
mutex_lock(&ops_mutex);
|
||||
ops->used--;
|
||||
}
|
||||
}
|
||||
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
|
||||
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) &&
|
||||
! (ops->driver & DRIVER_REQUESTED)) {
|
||||
ops->used++;
|
||||
mutex_unlock(&ops_mutex);
|
||||
ops->driver |= DRIVER_REQUESTED;
|
||||
request_module("snd-%s", ops->id);
|
||||
mutex_lock(&ops_mutex);
|
||||
ops->used--;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ops_mutex);
|
||||
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
|
||||
|
|
Загрузка…
Ссылка в новой задаче