Skip to content

Commit

Permalink
ALSA: firewire-tascam: deleyed registration of sound card
Browse files Browse the repository at this point in the history
When some tascam 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 <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
takaswie authored and tiwai committed Apr 25, 2016
1 parent d23f051 commit b610386
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 36 deletions.
118 changes: 82 additions & 36 deletions sound/firewire/tascam/tascam.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,8 @@ static int identify_model(struct snd_tscm *tscm)
return 0;
}

static void tscm_card_free(struct snd_card *card)
static void tscm_free(struct snd_tscm *tscm)
{
struct snd_tscm *tscm = card->private_data;

snd_tscm_transaction_unregister(tscm);
snd_tscm_stream_destroy_duplex(tscm);

Expand All @@ -97,44 +95,36 @@ static void tscm_card_free(struct snd_card *card)
mutex_destroy(&tscm->mutex);
}

static int snd_tscm_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
static void tscm_card_free(struct snd_card *card)
{
struct snd_card *card;
struct snd_tscm *tscm;
tscm_free(card->private_data);
}

static void do_registration(struct work_struct *work)
{
struct snd_tscm *tscm = container_of(work, struct snd_tscm, dwork.work);
int err;

/* create card */
err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
sizeof(struct snd_tscm), &card);
err = snd_card_new(&tscm->unit->device, -1, NULL, THIS_MODULE, 0,
&tscm->card);
if (err < 0)
return err;
card->private_free = tscm_card_free;

/* initialize myself */
tscm = card->private_data;
tscm->card = card;
tscm->unit = fw_unit_get(unit);

mutex_init(&tscm->mutex);
spin_lock_init(&tscm->lock);
init_waitqueue_head(&tscm->hwdep_wait);
return;

err = identify_model(tscm);
if (err < 0)
goto error;

snd_tscm_proc_init(tscm);

err = snd_tscm_stream_init_duplex(tscm);
err = snd_tscm_transaction_register(tscm);
if (err < 0)
goto error;

err = snd_tscm_create_pcm_devices(tscm);
err = snd_tscm_stream_init_duplex(tscm);
if (err < 0)
goto error;

err = snd_tscm_transaction_register(tscm);
snd_tscm_proc_init(tscm);

err = snd_tscm_create_pcm_devices(tscm);
if (err < 0)
goto error;

Expand All @@ -146,35 +136,91 @@ static int snd_tscm_probe(struct fw_unit *unit,
if (err < 0)
goto error;

err = snd_card_register(card);
err = snd_card_register(tscm->card);
if (err < 0)
goto error;

dev_set_drvdata(&unit->device, tscm);
/*
* After registered, tscm instance can be released corresponding to
* releasing the sound card instance.
*/
tscm->card->private_free = tscm_card_free;
tscm->card->private_data = tscm;
tscm->registered = true;

return err;
return;
error:
snd_card_free(card);
return err;
snd_tscm_transaction_unregister(tscm);
snd_tscm_stream_destroy_duplex(tscm);
snd_card_free(tscm->card);
dev_info(&tscm->unit->device,
"Sound card registration failed: %d\n", err);
}

static int snd_tscm_probe(struct fw_unit *unit,
const struct ieee1394_device_id *entry)
{
struct snd_tscm *tscm;

/* Allocate this independent of sound card instance. */
tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
if (tscm == NULL)
return -ENOMEM;

/* initialize myself */
tscm->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, tscm);

mutex_init(&tscm->mutex);
spin_lock_init(&tscm->lock);
init_waitqueue_head(&tscm->hwdep_wait);

/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&tscm->dwork, do_registration);
snd_fw_schedule_registration(unit, &tscm->dwork);

return 0;
}

static void snd_tscm_update(struct fw_unit *unit)
{
struct snd_tscm *tscm = dev_get_drvdata(&unit->device);

/* Postpone a workqueue for deferred registration. */
if (!tscm->registered)
snd_fw_schedule_registration(unit, &tscm->dwork);

snd_tscm_transaction_reregister(tscm);

mutex_lock(&tscm->mutex);
snd_tscm_stream_update_duplex(tscm);
mutex_unlock(&tscm->mutex);
/*
* After registration, userspace can start packet streaming, then this
* code block works fine.
*/
if (tscm->registered) {
mutex_lock(&tscm->mutex);
snd_tscm_stream_update_duplex(tscm);
mutex_unlock(&tscm->mutex);
}
}

static void snd_tscm_remove(struct fw_unit *unit)
{
struct snd_tscm *tscm = dev_get_drvdata(&unit->device);

/* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(tscm->card);
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&tscm->dwork);

if (tscm->registered) {
/* No need to wait for releasing card object in this context. */
snd_card_free_when_closed(tscm->card);
} else {
/* Don't forget this case. */
tscm_free(tscm);
}
}

static const struct ieee1394_device_id snd_tscm_id_table[] = {
Expand Down
2 changes: 2 additions & 0 deletions sound/firewire/tascam/tascam.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ struct snd_tscm {
struct mutex mutex;
spinlock_t lock;

bool registered;
struct delayed_work dwork;
const struct snd_tscm_spec *spec;

struct fw_iso_resources tx_resources;
Expand Down

0 comments on commit b610386

Please sign in to comment.