aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2016-03-30 19:47:09 -0400
committerTakashi Iwai <tiwai@suse.de>2016-04-25 04:40:42 -0400
commitb610386c8afba397238329c50c45a3abc79ba45f (patch)
tree0e80823c33eb20df300c5de5f6f1b44effcd9aa3
parentd23f0517357ef48d2845846e899d125b3c1a492e (diff)
ALSA: firewire-tascam: deleyed registration of sound card
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>
-rw-r--r--sound/firewire/tascam/tascam.c118
-rw-r--r--sound/firewire/tascam/tascam.h2
2 files changed, 84 insertions, 36 deletions
diff --git a/sound/firewire/tascam/tascam.c b/sound/firewire/tascam/tascam.c
index e281c338e562..9dc93a7eb9da 100644
--- a/sound/firewire/tascam/tascam.c
+++ b/sound/firewire/tascam/tascam.c
@@ -85,10 +85,8 @@ static int identify_model(struct snd_tscm *tscm)
85 return 0; 85 return 0;
86} 86}
87 87
88static void tscm_card_free(struct snd_card *card) 88static void tscm_free(struct snd_tscm *tscm)
89{ 89{
90 struct snd_tscm *tscm = card->private_data;
91
92 snd_tscm_transaction_unregister(tscm); 90 snd_tscm_transaction_unregister(tscm);
93 snd_tscm_stream_destroy_duplex(tscm); 91 snd_tscm_stream_destroy_duplex(tscm);
94 92
@@ -97,44 +95,36 @@ static void tscm_card_free(struct snd_card *card)
97 mutex_destroy(&tscm->mutex); 95 mutex_destroy(&tscm->mutex);
98} 96}
99 97
100static int snd_tscm_probe(struct fw_unit *unit, 98static void tscm_card_free(struct snd_card *card)
101 const struct ieee1394_device_id *entry)
102{ 99{
103 struct snd_card *card; 100 tscm_free(card->private_data);
104 struct snd_tscm *tscm; 101}
102
103static void do_registration(struct work_struct *work)
104{
105 struct snd_tscm *tscm = container_of(work, struct snd_tscm, dwork.work);
105 int err; 106 int err;
106 107
107 /* create card */ 108 err = snd_card_new(&tscm->unit->device, -1, NULL, THIS_MODULE, 0,
108 err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, 109 &tscm->card);
109 sizeof(struct snd_tscm), &card);
110 if (err < 0) 110 if (err < 0)
111 return err; 111 return;
112 card->private_free = tscm_card_free;
113
114 /* initialize myself */
115 tscm = card->private_data;
116 tscm->card = card;
117 tscm->unit = fw_unit_get(unit);
118
119 mutex_init(&tscm->mutex);
120 spin_lock_init(&tscm->lock);
121 init_waitqueue_head(&tscm->hwdep_wait);
122 112
123 err = identify_model(tscm); 113 err = identify_model(tscm);
124 if (err < 0) 114 if (err < 0)
125 goto error; 115 goto error;
126 116
127 snd_tscm_proc_init(tscm); 117 err = snd_tscm_transaction_register(tscm);
128
129 err = snd_tscm_stream_init_duplex(tscm);
130 if (err < 0) 118 if (err < 0)
131 goto error; 119 goto error;
132 120
133 err = snd_tscm_create_pcm_devices(tscm); 121 err = snd_tscm_stream_init_duplex(tscm);
134 if (err < 0) 122 if (err < 0)
135 goto error; 123 goto error;
136 124
137 err = snd_tscm_transaction_register(tscm); 125 snd_tscm_proc_init(tscm);
126
127 err = snd_tscm_create_pcm_devices(tscm);
138 if (err < 0) 128 if (err < 0)
139 goto error; 129 goto error;
140 130
@@ -146,35 +136,91 @@ static int snd_tscm_probe(struct fw_unit *unit,
146 if (err < 0) 136 if (err < 0)
147 goto error; 137 goto error;
148 138
149 err = snd_card_register(card); 139 err = snd_card_register(tscm->card);
150 if (err < 0) 140 if (err < 0)
151 goto error; 141 goto error;
152 142
153 dev_set_drvdata(&unit->device, tscm); 143 /*
144 * After registered, tscm instance can be released corresponding to
145 * releasing the sound card instance.
146 */
147 tscm->card->private_free = tscm_card_free;
148 tscm->card->private_data = tscm;
149 tscm->registered = true;
154 150
155 return err; 151 return;
156error: 152error:
157 snd_card_free(card); 153 snd_tscm_transaction_unregister(tscm);
158 return err; 154 snd_tscm_stream_destroy_duplex(tscm);
155 snd_card_free(tscm->card);
156 dev_info(&tscm->unit->device,
157 "Sound card registration failed: %d\n", err);
158}
159
160static int snd_tscm_probe(struct fw_unit *unit,
161 const struct ieee1394_device_id *entry)
162{
163 struct snd_tscm *tscm;
164
165 /* Allocate this independent of sound card instance. */
166 tscm = kzalloc(sizeof(struct snd_tscm), GFP_KERNEL);
167 if (tscm == NULL)
168 return -ENOMEM;
169
170 /* initialize myself */
171 tscm->unit = fw_unit_get(unit);
172 dev_set_drvdata(&unit->device, tscm);
173
174 mutex_init(&tscm->mutex);
175 spin_lock_init(&tscm->lock);
176 init_waitqueue_head(&tscm->hwdep_wait);
177
178 /* Allocate and register this sound card later. */
179 INIT_DEFERRABLE_WORK(&tscm->dwork, do_registration);
180 snd_fw_schedule_registration(unit, &tscm->dwork);
181
182 return 0;
159} 183}
160 184
161static void snd_tscm_update(struct fw_unit *unit) 185static void snd_tscm_update(struct fw_unit *unit)
162{ 186{
163 struct snd_tscm *tscm = dev_get_drvdata(&unit->device); 187 struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
164 188
189 /* Postpone a workqueue for deferred registration. */
190 if (!tscm->registered)
191 snd_fw_schedule_registration(unit, &tscm->dwork);
192
165 snd_tscm_transaction_reregister(tscm); 193 snd_tscm_transaction_reregister(tscm);
166 194
167 mutex_lock(&tscm->mutex); 195 /*
168 snd_tscm_stream_update_duplex(tscm); 196 * After registration, userspace can start packet streaming, then this
169 mutex_unlock(&tscm->mutex); 197 * code block works fine.
198 */
199 if (tscm->registered) {
200 mutex_lock(&tscm->mutex);
201 snd_tscm_stream_update_duplex(tscm);
202 mutex_unlock(&tscm->mutex);
203 }
170} 204}
171 205
172static void snd_tscm_remove(struct fw_unit *unit) 206static void snd_tscm_remove(struct fw_unit *unit)
173{ 207{
174 struct snd_tscm *tscm = dev_get_drvdata(&unit->device); 208 struct snd_tscm *tscm = dev_get_drvdata(&unit->device);
175 209
176 /* No need to wait for releasing card object in this context. */ 210 /*
177 snd_card_free_when_closed(tscm->card); 211 * Confirm to stop the work for registration before the sound card is
212 * going to be released. The work is not scheduled again because bus
213 * reset handler is not called anymore.
214 */
215 cancel_delayed_work_sync(&tscm->dwork);
216
217 if (tscm->registered) {
218 /* No need to wait for releasing card object in this context. */
219 snd_card_free_when_closed(tscm->card);
220 } else {
221 /* Don't forget this case. */
222 tscm_free(tscm);
223 }
178} 224}
179 225
180static const struct ieee1394_device_id snd_tscm_id_table[] = { 226static const struct ieee1394_device_id snd_tscm_id_table[] = {
diff --git a/sound/firewire/tascam/tascam.h b/sound/firewire/tascam/tascam.h
index 30ab77e924f7..1f61011579a7 100644
--- a/sound/firewire/tascam/tascam.h
+++ b/sound/firewire/tascam/tascam.h
@@ -51,6 +51,8 @@ struct snd_tscm {
51 struct mutex mutex; 51 struct mutex mutex;
52 spinlock_t lock; 52 spinlock_t lock;
53 53
54 bool registered;
55 struct delayed_work dwork;
54 const struct snd_tscm_spec *spec; 56 const struct snd_tscm_spec *spec;
55 57
56 struct fw_iso_resources tx_resources; 58 struct fw_iso_resources tx_resources;