static void efw_remove(struct fw_unit *unit) { struct snd_efw *efw = dev_get_drvdata(&unit->device); snd_efw_stream_destroy_duplex(efw); snd_efw_transaction_remove_instance(efw); snd_card_disconnect(efw->card); snd_card_free_when_closed(efw->card); }
/* * This module releases the FireWire unit data after all ALSA character devices * are released by applications. This is for releasing stream data or finishing * transactions safely. Thus at returning from .remove(), this module still keep * references for the unit. */ static void efw_card_free(struct snd_card *card) { 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) { mutex_lock(&devices_mutex); clear_bit(efw->card_index, devices_used); mutex_unlock(&devices_mutex); } mutex_destroy(&efw->mutex); }
static int efw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) { struct snd_card *card; struct snd_efw *efw; int card_index, err; mutex_lock(&devices_mutex); /* check registered cards */ for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) { if (!test_bit(card_index, devices_used) && enable[card_index]) break; } if (card_index >= SNDRV_CARDS) { err = -ENOENT; goto end; } err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE, sizeof(struct snd_efw), &card); if (err < 0) goto end; efw = card->private_data; efw->card_index = card_index; set_bit(card_index, devices_used); card->private_free = efw_card_free; efw->card = card; efw->unit = unit; mutex_init(&efw->mutex); spin_lock_init(&efw->lock); init_waitqueue_head(&efw->hwdep_wait); /* prepare response buffer */ snd_efw_resp_buf_size = clamp(snd_efw_resp_buf_size, SND_EFW_RESPONSE_MAXIMUM_BYTES, 4096U); efw->resp_buf = kzalloc(snd_efw_resp_buf_size, GFP_KERNEL); if (efw->resp_buf == NULL) { err = -ENOMEM; goto error; } efw->pull_ptr = efw->push_ptr = efw->resp_buf; snd_efw_transaction_add_instance(efw); err = get_hardware_info(efw); if (err < 0) goto error; if (entry->model_id == MODEL_ECHO_AUDIOFIRE_9) efw->is_af9 = true; snd_efw_proc_init(efw); if (efw->midi_out_ports || efw->midi_in_ports) { err = snd_efw_create_midi_devices(efw); if (err < 0) goto error; } err = snd_efw_create_pcm_devices(efw); if (err < 0) goto error; err = snd_efw_create_hwdep_device(efw); if (err < 0) goto error; err = snd_efw_stream_init_duplex(efw); if (err < 0) goto error; err = snd_card_register(card); if (err < 0) { snd_efw_stream_destroy_duplex(efw); goto error; } dev_set_drvdata(&unit->device, efw); end: mutex_unlock(&devices_mutex); return err; error: snd_efw_transaction_remove_instance(efw); mutex_unlock(&devices_mutex); snd_card_free(card); return err; }