提交 b566762a 编写于 作者: T Takashi Iwai

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

无相关合并请求
...@@ -108,9 +108,13 @@ int snd_seq_event_port_detach(int client, int port); ...@@ -108,9 +108,13 @@ int snd_seq_event_port_detach(int client, int port);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
void snd_seq_autoload_lock(void); void snd_seq_autoload_lock(void);
void snd_seq_autoload_unlock(void); void snd_seq_autoload_unlock(void);
void snd_seq_autoload_init(void);
#define snd_seq_autoload_exit() snd_seq_autoload_lock()
#else #else
#define snd_seq_autoload_lock() #define snd_seq_autoload_lock()
#define snd_seq_autoload_unlock() #define snd_seq_autoload_unlock()
#define snd_seq_autoload_init()
#define snd_seq_autoload_exit()
#endif #endif
#endif /* __SOUND_SEQ_KERNEL_H */ #endif /* __SOUND_SEQ_KERNEL_H */
...@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void) ...@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void)
{ {
int err; int err;
snd_seq_autoload_lock();
if ((err = client_init_data()) < 0) if ((err = client_init_data()) < 0)
goto error; goto error;
...@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void) ...@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void)
if ((err = snd_seq_system_client_init()) < 0) if ((err = snd_seq_system_client_init()) < 0)
goto error; goto error;
snd_seq_autoload_init();
error: error:
snd_seq_autoload_unlock();
return err; return err;
} }
...@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void) ...@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void)
/* release event memory */ /* release event memory */
snd_sequencer_memory_done(); snd_sequencer_memory_done();
snd_seq_autoload_exit();
} }
module_init(alsa_seq_init) module_init(alsa_seq_init)
......
...@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL"); ...@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
#define DRIVER_LOADED (1<<0) #define DRIVER_LOADED (1<<0)
#define DRIVER_REQUESTED (1<<1) #define DRIVER_REQUESTED (1<<1)
#define DRIVER_LOCKED (1<<2) #define DRIVER_LOCKED (1<<2)
#define DRIVER_REQUESTING (1<<3)
struct ops_list { struct ops_list {
char id[ID_LEN]; /* driver id */ char id[ID_LEN]; /* driver id */
...@@ -127,42 +128,82 @@ static void snd_seq_device_info(struct snd_info_entry *entry, ...@@ -127,42 +128,82 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */ /* 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) void snd_seq_autoload_lock(void)
{ {
snd_seq_in_init++; atomic_inc(&snd_seq_in_init);
} }
void snd_seq_autoload_unlock(void) 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 */
struct ops_list *ops; 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);
}
/* Calling request_module during module_init() static void call_autoload(struct work_struct *work)
* may cause blocking. {
*/ autoload_drivers();
if (snd_seq_in_init) }
return;
mutex_lock(&ops_mutex); static DECLARE_WORK(autoload_work, call_autoload);
list_for_each_entry(ops, &opslist, list) {
if (! (ops->driver & DRIVER_LOADED) && static void try_autoload(struct ops_list *ops)
! (ops->driver & DRIVER_REQUESTED)) { {
ops->used++; if (!ops->driver) {
mutex_unlock(&ops_mutex); ops->driver |= DRIVER_REQUESTING;
ops->driver |= DRIVER_REQUESTED; schedule_work(&autoload_work);
request_module("snd-%s", ops->id);
mutex_lock(&ops_mutex);
ops->used--;
}
} }
}
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); 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 #endif
} }
...@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, ...@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
ops->num_devices++; ops->num_devices++;
mutex_unlock(&ops->reg_mutex); mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
snd_seq_device_free(dev); snd_seq_device_free(dev);
return err; return err;
} }
try_autoload(ops);
unlock_driver(ops);
if (result) if (result)
*result = dev; *result = dev;
...@@ -318,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, ...@@ -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) entry->init_device == NULL || entry->free_device == NULL)
return -EINVAL; return -EINVAL;
snd_seq_autoload_lock();
ops = find_driver(id, 1); ops = find_driver(id, 1);
if (ops == NULL) { if (ops == NULL)
snd_seq_autoload_unlock();
return -ENOMEM; return -ENOMEM;
}
if (ops->driver & DRIVER_LOADED) { if (ops->driver & DRIVER_LOADED) {
pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id); pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops); unlock_driver(ops);
snd_seq_autoload_unlock();
return -EBUSY; return -EBUSY;
} }
...@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, ...@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
mutex_unlock(&ops->reg_mutex); mutex_unlock(&ops->reg_mutex);
unlock_driver(ops); unlock_driver(ops);
snd_seq_autoload_unlock();
return 0; return 0;
} }
...@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void) ...@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void)
static void __exit alsa_seq_device_exit(void) static void __exit alsa_seq_device_exit(void)
{ {
#ifdef CONFIG_MODULES
cancel_work_sync(&autoload_work);
#endif
remove_drivers(); remove_drivers();
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
snd_info_free_entry(info_entry); snd_info_free_entry(info_entry);
...@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new); ...@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver); EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver); EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock); EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock); EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif #endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部