aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/core/seq/seq.c3
-rw-r--r--sound/core/seq/seq_device.c92
2 files changed, 72 insertions, 23 deletions
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 712110561082..bebdd2e920ca 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -110,6 +110,7 @@ static int __init alsa_seq_init(void)
110 if ((err = snd_seq_system_client_init()) < 0) 110 if ((err = snd_seq_system_client_init()) < 0)
111 goto error; 111 goto error;
112 112
113 snd_seq_autoload_init();
113 error: 114 error:
114 snd_seq_autoload_unlock(); 115 snd_seq_autoload_unlock();
115 return err; 116 return err;
@@ -131,6 +132,8 @@ static void __exit alsa_seq_exit(void)
131 132
132 /* release event memory */ 133 /* release event memory */
133 snd_sequencer_memory_done(); 134 snd_sequencer_memory_done();
135
136 snd_seq_autoload_exit();
134} 137}
135 138
136module_init(alsa_seq_init) 139module_init(alsa_seq_init)
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 775ea9390110..a8e2c6016800 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
56#define DRIVER_LOADED (1<<0) 56#define DRIVER_LOADED (1<<0)
57#define DRIVER_REQUESTED (1<<1) 57#define DRIVER_REQUESTED (1<<1)
58#define DRIVER_LOCKED (1<<2) 58#define DRIVER_LOCKED (1<<2)
59#define DRIVER_REQUESTING (1<<3)
59 60
60struct ops_list { 61struct ops_list {
61 char id[ID_LEN]; /* driver id */ 62 char id[ID_LEN]; /* driver id */
@@ -127,7 +128,7 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
127 128
128#ifdef CONFIG_MODULES 129#ifdef CONFIG_MODULES
129/* avoid auto-loading during module_init() */ 130/* avoid auto-loading during module_init() */
130static atomic_t snd_seq_in_init = ATOMIC_INIT(0); 131static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
131void snd_seq_autoload_lock(void) 132void snd_seq_autoload_lock(void)
132{ 133{
133 atomic_inc(&snd_seq_in_init); 134 atomic_inc(&snd_seq_in_init);
@@ -137,32 +138,72 @@ void snd_seq_autoload_unlock(void)
137{ 138{
138 atomic_dec(&snd_seq_in_init); 139 atomic_dec(&snd_seq_in_init);
139} 140}
140#endif
141 141
142void snd_seq_device_load_drivers(void) 142static void autoload_drivers(void)
143{ 143{
144#ifdef CONFIG_MODULES 144 /* avoid reentrance */
145 struct ops_list *ops; 145 if (atomic_inc_return(&snd_seq_in_init) == 1) {
146 struct ops_list *ops;
147
148 mutex_lock(&ops_mutex);
149 list_for_each_entry(ops, &opslist, list) {
150 if ((ops->driver & DRIVER_REQUESTING) &&
151 !(ops->driver & DRIVER_REQUESTED)) {
152 ops->used++;
153 mutex_unlock(&ops_mutex);
154 ops->driver |= DRIVER_REQUESTED;
155 request_module("snd-%s", ops->id);
156 mutex_lock(&ops_mutex);
157 ops->used--;
158 }
159 }
160 mutex_unlock(&ops_mutex);
161 }
162 atomic_dec(&snd_seq_in_init);
163}
146 164
147 /* Calling request_module during module_init() 165static void call_autoload(struct work_struct *work)
148 * may cause blocking. 166{
149 */ 167 autoload_drivers();
150 if (atomic_read(&snd_seq_in_init)) 168}
151 return;
152 169
153 mutex_lock(&ops_mutex); 170static DECLARE_WORK(autoload_work, call_autoload);
154 list_for_each_entry(ops, &opslist, list) { 171
155 if (! (ops->driver & DRIVER_LOADED) && 172static void try_autoload(struct ops_list *ops)
156 ! (ops->driver & DRIVER_REQUESTED)) { 173{
157 ops->used++; 174 if (!ops->driver) {
158 mutex_unlock(&ops_mutex); 175 ops->driver |= DRIVER_REQUESTING;
159 ops->driver |= DRIVER_REQUESTED; 176 schedule_work(&autoload_work);
160 request_module("snd-%s", ops->id);
161 mutex_lock(&ops_mutex);
162 ops->used--;
163 }
164 } 177 }
178}
179
180static void queue_autoload_drivers(void)
181{
182 struct ops_list *ops;
183
184 mutex_lock(&ops_mutex);
185 list_for_each_entry(ops, &opslist, list)
186 try_autoload(ops);
165 mutex_unlock(&ops_mutex); 187 mutex_unlock(&ops_mutex);
188}
189
190void snd_seq_autoload_init(void)
191{
192 atomic_dec(&snd_seq_in_init);
193#ifdef CONFIG_SND_SEQUENCER_MODULE
194 /* initial autoload only when snd-seq is a module */
195 queue_autoload_drivers();
196#endif
197}
198#else
199#define try_autoload(ops) /* NOP */
200#endif
201
202void snd_seq_device_load_drivers(void)
203{
204#ifdef CONFIG_MODULES
205 queue_autoload_drivers();
206 flush_work(&autoload_work);
166#endif 207#endif
167} 208}
168 209
@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
214 ops->num_devices++; 255 ops->num_devices++;
215 mutex_unlock(&ops->reg_mutex); 256 mutex_unlock(&ops->reg_mutex);
216 257
217 unlock_driver(ops);
218
219 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { 258 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
220 snd_seq_device_free(dev); 259 snd_seq_device_free(dev);
221 return err; 260 return err;
222 } 261 }
223 262
263 try_autoload(ops);
264 unlock_driver(ops);
265
224 if (result) 266 if (result)
225 *result = dev; 267 *result = dev;
226 268
@@ -554,6 +596,9 @@ static int __init alsa_seq_device_init(void)
554 596
555static void __exit alsa_seq_device_exit(void) 597static void __exit alsa_seq_device_exit(void)
556{ 598{
599#ifdef CONFIG_MODULES
600 cancel_work_sync(&autoload_work);
601#endif
557 remove_drivers(); 602 remove_drivers();
558#ifdef CONFIG_PROC_FS 603#ifdef CONFIG_PROC_FS
559 snd_info_free_entry(info_entry); 604 snd_info_free_entry(info_entry);
@@ -570,6 +615,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
570EXPORT_SYMBOL(snd_seq_device_register_driver); 615EXPORT_SYMBOL(snd_seq_device_register_driver);
571EXPORT_SYMBOL(snd_seq_device_unregister_driver); 616EXPORT_SYMBOL(snd_seq_device_unregister_driver);
572#ifdef CONFIG_MODULES 617#ifdef CONFIG_MODULES
618EXPORT_SYMBOL(snd_seq_autoload_init);
573EXPORT_SYMBOL(snd_seq_autoload_lock); 619EXPORT_SYMBOL(snd_seq_autoload_lock);
574EXPORT_SYMBOL(snd_seq_autoload_unlock); 620EXPORT_SYMBOL(snd_seq_autoload_unlock);
575#endif 621#endif