mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-20 05:13:59 +00:00
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 <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
04a2c73c97
commit
7d3c1d5901
2 changed files with 103 additions and 47 deletions
|
@ -184,6 +184,18 @@ end:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void efw_free(struct snd_efw *efw)
|
||||||
|
{
|
||||||
|
snd_efw_stream_destroy_duplex(efw);
|
||||||
|
snd_efw_transaction_remove_instance(efw);
|
||||||
|
fw_unit_put(efw->unit);
|
||||||
|
|
||||||
|
kfree(efw->resp_buf);
|
||||||
|
|
||||||
|
mutex_destroy(&efw->mutex);
|
||||||
|
kfree(efw);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This module releases the FireWire unit data after all ALSA character devices
|
* This module releases the FireWire unit data after all ALSA character devices
|
||||||
* are released by applications. This is for releasing stream data or finishing
|
* are released by applications. This is for releasing stream data or finishing
|
||||||
|
@ -195,28 +207,24 @@ efw_card_free(struct snd_card *card)
|
||||||
{
|
{
|
||||||
struct snd_efw *efw = card->private_data;
|
struct snd_efw *efw = card->private_data;
|
||||||
|
|
||||||
snd_efw_stream_destroy_duplex(efw);
|
|
||||||
snd_efw_transaction_remove_instance(efw);
|
|
||||||
fw_unit_put(efw->unit);
|
|
||||||
|
|
||||||
kfree(efw->resp_buf);
|
|
||||||
|
|
||||||
if (efw->card_index >= 0) {
|
if (efw->card_index >= 0) {
|
||||||
mutex_lock(&devices_mutex);
|
mutex_lock(&devices_mutex);
|
||||||
clear_bit(efw->card_index, devices_used);
|
clear_bit(efw->card_index, devices_used);
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_unlock(&devices_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_destroy(&efw->mutex);
|
efw_free(card->private_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
efw_probe(struct fw_unit *unit,
|
do_registration(struct work_struct *work)
|
||||||
const struct ieee1394_device_id *entry)
|
|
||||||
{
|
{
|
||||||
struct snd_card *card;
|
struct snd_efw *efw = container_of(work, struct snd_efw, dwork.work);
|
||||||
struct snd_efw *efw;
|
unsigned int card_index;
|
||||||
int card_index, err;
|
int err;
|
||||||
|
|
||||||
|
if (efw->registered)
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&devices_mutex);
|
mutex_lock(&devices_mutex);
|
||||||
|
|
||||||
|
@ -226,24 +234,16 @@ efw_probe(struct fw_unit *unit,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (card_index >= SNDRV_CARDS) {
|
if (card_index >= SNDRV_CARDS) {
|
||||||
err = -ENOENT;
|
mutex_unlock(&devices_mutex);
|
||||||
goto end;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_card_new(&unit->device, index[card_index], id[card_index],
|
err = snd_card_new(&efw->unit->device, index[card_index],
|
||||||
THIS_MODULE, sizeof(struct snd_efw), &card);
|
id[card_index], THIS_MODULE, 0, &efw->card);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
goto end;
|
mutex_unlock(&devices_mutex);
|
||||||
efw = card->private_data;
|
return;
|
||||||
efw->card_index = card_index;
|
}
|
||||||
set_bit(card_index, devices_used);
|
|
||||||
card->private_free = efw_card_free;
|
|
||||||
|
|
||||||
efw->card = card;
|
|
||||||
efw->unit = fw_unit_get(unit);
|
|
||||||
mutex_init(&efw->mutex);
|
|
||||||
spin_lock_init(&efw->lock);
|
|
||||||
init_waitqueue_head(&efw->hwdep_wait);
|
|
||||||
|
|
||||||
/* prepare response buffer */
|
/* prepare response buffer */
|
||||||
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
|
snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size,
|
||||||
|
@ -260,6 +260,10 @@ efw_probe(struct fw_unit *unit,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
err = snd_efw_stream_init_duplex(efw);
|
||||||
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
snd_efw_proc_init(efw);
|
snd_efw_proc_init(efw);
|
||||||
|
|
||||||
if (efw->midi_out_ports || efw->midi_in_ports) {
|
if (efw->midi_out_ports || efw->midi_in_ports) {
|
||||||
|
@ -276,44 +280,93 @@ efw_probe(struct fw_unit *unit,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
err = snd_efw_stream_init_duplex(efw);
|
err = snd_card_register(efw->card);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
err = snd_card_register(card);
|
set_bit(card_index, devices_used);
|
||||||
if (err < 0) {
|
mutex_unlock(&devices_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After registered, efw instance can be released corresponding to
|
||||||
|
* releasing the sound card instance.
|
||||||
|
*/
|
||||||
|
efw->card->private_free = efw_card_free;
|
||||||
|
efw->card->private_data = efw;
|
||||||
|
efw->registered = true;
|
||||||
|
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
mutex_unlock(&devices_mutex);
|
||||||
|
snd_efw_transaction_remove_instance(efw);
|
||||||
snd_efw_stream_destroy_duplex(efw);
|
snd_efw_stream_destroy_duplex(efw);
|
||||||
goto error;
|
snd_card_free(efw->card);
|
||||||
|
dev_info(&efw->unit->device,
|
||||||
|
"Sound card registration failed: %d\n", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
|
||||||
|
{
|
||||||
|
struct snd_efw *efw;
|
||||||
|
|
||||||
|
efw = kzalloc(sizeof(struct snd_efw), GFP_KERNEL);
|
||||||
|
if (efw == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
efw->unit = fw_unit_get(unit);
|
||||||
dev_set_drvdata(&unit->device, efw);
|
dev_set_drvdata(&unit->device, efw);
|
||||||
end:
|
|
||||||
mutex_unlock(&devices_mutex);
|
mutex_init(&efw->mutex);
|
||||||
return err;
|
spin_lock_init(&efw->lock);
|
||||||
error:
|
init_waitqueue_head(&efw->hwdep_wait);
|
||||||
snd_efw_transaction_remove_instance(efw);
|
|
||||||
mutex_unlock(&devices_mutex);
|
/* Allocate and register this sound card later. */
|
||||||
snd_card_free(card);
|
INIT_DEFERRABLE_WORK(&efw->dwork, do_registration);
|
||||||
return err;
|
snd_fw_schedule_registration(unit, &efw->dwork);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void efw_update(struct fw_unit *unit)
|
static void efw_update(struct fw_unit *unit)
|
||||||
{
|
{
|
||||||
struct snd_efw *efw = dev_get_drvdata(&unit->device);
|
struct snd_efw *efw = dev_get_drvdata(&unit->device);
|
||||||
|
|
||||||
|
/* Postpone a workqueue for deferred registration. */
|
||||||
|
if (!efw->registered)
|
||||||
|
snd_fw_schedule_registration(unit, &efw->dwork);
|
||||||
|
|
||||||
snd_efw_transaction_bus_reset(efw->unit);
|
snd_efw_transaction_bus_reset(efw->unit);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After registration, userspace can start packet streaming, then this
|
||||||
|
* code block works fine.
|
||||||
|
*/
|
||||||
|
if (efw->registered) {
|
||||||
mutex_lock(&efw->mutex);
|
mutex_lock(&efw->mutex);
|
||||||
snd_efw_stream_update_duplex(efw);
|
snd_efw_stream_update_duplex(efw);
|
||||||
mutex_unlock(&efw->mutex);
|
mutex_unlock(&efw->mutex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void efw_remove(struct fw_unit *unit)
|
static void efw_remove(struct fw_unit *unit)
|
||||||
{
|
{
|
||||||
struct snd_efw *efw = dev_get_drvdata(&unit->device);
|
struct snd_efw *efw = dev_get_drvdata(&unit->device);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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(&efw->dwork);
|
||||||
|
|
||||||
|
if (efw->registered) {
|
||||||
/* No need to wait for releasing card object in this context. */
|
/* No need to wait for releasing card object in this context. */
|
||||||
snd_card_free_when_closed(efw->card);
|
snd_card_free_when_closed(efw->card);
|
||||||
|
} else {
|
||||||
|
/* Don't forget this case. */
|
||||||
|
efw_free(efw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ieee1394_device_id efw_id_table[] = {
|
static const struct ieee1394_device_id efw_id_table[] = {
|
||||||
|
|
|
@ -65,6 +65,9 @@ struct snd_efw {
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
|
|
||||||
|
bool registered;
|
||||||
|
struct delayed_work dwork;
|
||||||
|
|
||||||
/* for transaction */
|
/* for transaction */
|
||||||
u32 seqnum;
|
u32 seqnum;
|
||||||
bool resp_addr_changable;
|
bool resp_addr_changable;
|
||||||
|
|
Loading…
Add table
Reference in a new issue