Skip to content

Commit 7d3c1d5

Browse files
takaswietiwai
authored andcommitted
ALSA: fireworks: delayed registration of sound card
When some fireworks units are connected sequentially, userspace applications are involved at bus-reset state on IEEE 1394 bus. In the state, any communications can be canceled. Therefore, sound card registration should be delayed till the bus gets calm. This commit achieves it. Signed-off-by: Takashi Sakamoto <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 04a2c73 commit 7d3c1d5

File tree

2 files changed

+103
-47
lines changed

2 files changed

+103
-47
lines changed

sound/firewire/fireworks/fireworks.c

Lines changed: 100 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ get_hardware_info(struct snd_efw *efw)
184184
return err;
185185
}
186186

187+
static void efw_free(struct snd_efw *efw)
188+
{
189+
snd_efw_stream_destroy_duplex(efw);
190+
snd_efw_transaction_remove_instance(efw);
191+
fw_unit_put(efw->unit);
192+
193+
kfree(efw->resp_buf);
194+
195+
mutex_destroy(&efw->mutex);
196+
kfree(efw);
197+
}
198+
187199
/*
188200
* This module releases the FireWire unit data after all ALSA character devices
189201
* are released by applications. This is for releasing stream data or finishing
@@ -195,28 +207,24 @@ efw_card_free(struct snd_card *card)
195207
{
196208
struct snd_efw *efw = card->private_data;
197209

198-
snd_efw_stream_destroy_duplex(efw);
199-
snd_efw_transaction_remove_instance(efw);
200-
fw_unit_put(efw->unit);
201-
202-
kfree(efw->resp_buf);
203-
204210
if (efw->card_index >= 0) {
205211
mutex_lock(&devices_mutex);
206212
clear_bit(efw->card_index, devices_used);
207213
mutex_unlock(&devices_mutex);
208214
}
209215

210-
mutex_destroy(&efw->mutex);
216+
efw_free(card->private_data);
211217
}
212218

213-
static int
214-
efw_probe(struct fw_unit *unit,
215-
const struct ieee1394_device_id *entry)
219+
static void
220+
do_registration(struct work_struct *work)
216221
{
217-
struct snd_card *card;
218-
struct snd_efw *efw;
219-
int card_index, err;
222+
struct snd_efw *efw = container_of(work, struct snd_efw, dwork.work);
223+
unsigned int card_index;
224+
int err;
225+
226+
if (efw->registered)
227+
return;
220228

221229
mutex_lock(&devices_mutex);
222230

@@ -226,24 +234,16 @@ efw_probe(struct fw_unit *unit,
226234
break;
227235
}
228236
if (card_index >= SNDRV_CARDS) {
229-
err = -ENOENT;
230-
goto end;
237+
mutex_unlock(&devices_mutex);
238+
return;
231239
}
232240

233-
err = snd_card_new(&unit->device, index[card_index], id[card_index],
234-
THIS_MODULE, sizeof(struct snd_efw), &card);
235-
if (err < 0)
236-
goto end;
237-
efw = card->private_data;
238-
efw->card_index = card_index;
239-
set_bit(card_index, devices_used);
240-
card->private_free = efw_card_free;
241-
242-
efw->card = card;
243-
efw->unit = fw_unit_get(unit);
244-
mutex_init(&efw->mutex);
245-
spin_lock_init(&efw->lock);
246-
init_waitqueue_head(&efw->hwdep_wait);
241+
err = snd_card_new(&efw->unit->device, index[card_index],
242+
id[card_index], THIS_MODULE, 0, &efw->card);
243+
if (err < 0) {
244+
mutex_unlock(&devices_mutex);
245+
return;
246+
}
247247

248248
/* prepare response buffer */
249249
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
@@ -260,6 +260,10 @@ efw_probe(struct fw_unit *unit,
260260
if (err < 0)
261261
goto error;
262262

263+
err = snd_efw_stream_init_duplex(efw);
264+
if (err < 0)
265+
goto error;
266+
263267
snd_efw_proc_init(efw);
264268

265269
if (efw->midi_out_ports || efw->midi_in_ports) {
@@ -276,44 +280,93 @@ efw_probe(struct fw_unit *unit,
276280
if (err < 0)
277281
goto error;
278282

279-
err = snd_efw_stream_init_duplex(efw);
283+
err = snd_card_register(efw->card);
280284
if (err < 0)
281285
goto error;
282286

283-
err = snd_card_register(card);
284-
if (err < 0) {
285-
snd_efw_stream_destroy_duplex(efw);
286-
goto error;
287-
}
288-
289-
dev_set_drvdata(&unit->device, efw);
290-
end:
287+
set_bit(card_index, devices_used);
291288
mutex_unlock(&devices_mutex);
292-
return err;
289+
290+
/*
291+
* After registered, efw instance can be released corresponding to
292+
* releasing the sound card instance.
293+
*/
294+
efw->card->private_free = efw_card_free;
295+
efw->card->private_data = efw;
296+
efw->registered = true;
297+
298+
return;
293299
error:
294-
snd_efw_transaction_remove_instance(efw);
295300
mutex_unlock(&devices_mutex);
296-
snd_card_free(card);
297-
return err;
301+
snd_efw_transaction_remove_instance(efw);
302+
snd_efw_stream_destroy_duplex(efw);
303+
snd_card_free(efw->card);
304+
dev_info(&efw->unit->device,
305+
"Sound card registration failed: %d\n", err);
306+
}
307+
308+
static int
309+
efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
310+
{
311+
struct snd_efw *efw;
312+
313+
efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL);
314+
if (efw == NULL)
315+
return -ENOMEM;
316+
317+
efw->unit = fw_unit_get(unit);
318+
dev_set_drvdata(&unit->device, efw);
319+
320+
mutex_init(&efw->mutex);
321+
spin_lock_init(&efw->lock);
322+
init_waitqueue_head(&efw->hwdep_wait);
323+
324+
/* Allocate and register this sound card later. */
325+
INIT_DEFERRABLE_WORK(&efw->dwork, do_registration);
326+
snd_fw_schedule_registration(unit, &efw->dwork);
327+
328+
return 0;
298329
}
299330

300331
static void efw_update(struct fw_unit *unit)
301332
{
302333
struct snd_efw *efw = dev_get_drvdata(&unit->device);
303334

335+
/* Postpone a workqueue for deferred registration. */
336+
if (!efw->registered)
337+
snd_fw_schedule_registration(unit, &efw->dwork);
338+
304339
snd_efw_transaction_bus_reset(efw->unit);
305340

306-
mutex_lock(&efw->mutex);
307-
snd_efw_stream_update_duplex(efw);
308-
mutex_unlock(&efw->mutex);
341+
/*
342+
* After registration, userspace can start packet streaming, then this
343+
* code block works fine.
344+
*/
345+
if (efw->registered) {
346+
mutex_lock(&efw->mutex);
347+
snd_efw_stream_update_duplex(efw);
348+
mutex_unlock(&efw->mutex);
349+
}
309350
}
310351

311352
static void efw_remove(struct fw_unit *unit)
312353
{
313354
struct snd_efw *efw = dev_get_drvdata(&unit->device);
314355

315-
/* No need to wait for releasing card object in this context. */
316-
snd_card_free_when_closed(efw->card);
356+
/*
357+
* Confirm to stop the work for registration before the sound card is
358+
* going to be released. The work is not scheduled again because bus
359+
* reset handler is not called anymore.
360+
*/
361+
cancel_delayed_work_sync(&efw->dwork);
362+
363+
if (efw->registered) {
364+
/* No need to wait for releasing card object in this context. */
365+
snd_card_free_when_closed(efw->card);
366+
} else {
367+
/* Don't forget this case. */
368+
efw_free(efw);
369+
}
317370
}
318371

319372
static const struct ieee1394_device_id efw_id_table[] = {

sound/firewire/fireworks/fireworks.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct snd_efw {
6565
struct mutex mutex;
6666
spinlock_t lock;
6767

68+
bool registered;
69+
struct delayed_work dwork;
70+
6871
/* for transaction */
6972
u32 seqnum;
7073
bool resp_addr_changable;

0 commit comments

Comments
 (0)