diff options
Diffstat (limited to 'sound/firewire')
-rw-r--r-- | sound/firewire/amdtp.c | 5 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob.c | 20 | ||||
-rw-r--r-- | sound/firewire/bebob/bebob_stream.c | 16 | ||||
-rw-r--r-- | sound/firewire/dice/dice-stream.c | 18 | ||||
-rw-r--r-- | sound/firewire/dice/dice.c | 16 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 20 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_stream.c | 19 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw-stream.c | 6 | ||||
-rw-r--r-- | sound/firewire/oxfw/oxfw.c | 21 |
9 files changed, 87 insertions, 54 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index 0d580186ef1a..5cc356db5351 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c | |||
@@ -33,7 +33,7 @@ | |||
33 | */ | 33 | */ |
34 | #define MAX_MIDI_RX_BLOCKS 8 | 34 | #define MAX_MIDI_RX_BLOCKS 8 |
35 | 35 | ||
36 | #define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 µs */ | 36 | #define TRANSFER_DELAY_TICKS 0x2e00 /* 479.17 microseconds */ |
37 | 37 | ||
38 | /* isochronous header parameters */ | 38 | /* isochronous header parameters */ |
39 | #define ISO_DATA_LENGTH_SHIFT 16 | 39 | #define ISO_DATA_LENGTH_SHIFT 16 |
@@ -78,7 +78,7 @@ static void pcm_period_tasklet(unsigned long data); | |||
78 | int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, | 78 | int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit, |
79 | enum amdtp_stream_direction dir, enum cip_flags flags) | 79 | enum amdtp_stream_direction dir, enum cip_flags flags) |
80 | { | 80 | { |
81 | s->unit = fw_unit_get(unit); | 81 | s->unit = unit; |
82 | s->direction = dir; | 82 | s->direction = dir; |
83 | s->flags = flags; | 83 | s->flags = flags; |
84 | s->context = ERR_PTR(-1); | 84 | s->context = ERR_PTR(-1); |
@@ -102,7 +102,6 @@ void amdtp_stream_destroy(struct amdtp_stream *s) | |||
102 | { | 102 | { |
103 | WARN_ON(amdtp_stream_running(s)); | 103 | WARN_ON(amdtp_stream_running(s)); |
104 | mutex_destroy(&s->mutex); | 104 | mutex_destroy(&s->mutex); |
105 | fw_unit_put(s->unit); | ||
106 | } | 105 | } |
107 | EXPORT_SYMBOL(amdtp_stream_destroy); | 106 | EXPORT_SYMBOL(amdtp_stream_destroy); |
108 | 107 | ||
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index fc19c99654aa..611b7dae7ee5 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c | |||
@@ -116,11 +116,22 @@ end: | |||
116 | return err; | 116 | return err; |
117 | } | 117 | } |
118 | 118 | ||
119 | /* | ||
120 | * This module releases the FireWire unit data after all ALSA character devices | ||
121 | * are released by applications. This is for releasing stream data or finishing | ||
122 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
123 | * references for the unit. | ||
124 | */ | ||
119 | static void | 125 | static void |
120 | bebob_card_free(struct snd_card *card) | 126 | bebob_card_free(struct snd_card *card) |
121 | { | 127 | { |
122 | struct snd_bebob *bebob = card->private_data; | 128 | struct snd_bebob *bebob = card->private_data; |
123 | 129 | ||
130 | snd_bebob_stream_destroy_duplex(bebob); | ||
131 | fw_unit_put(bebob->unit); | ||
132 | |||
133 | kfree(bebob->maudio_special_quirk); | ||
134 | |||
124 | if (bebob->card_index >= 0) { | 135 | if (bebob->card_index >= 0) { |
125 | mutex_lock(&devices_mutex); | 136 | mutex_lock(&devices_mutex); |
126 | clear_bit(bebob->card_index, devices_used); | 137 | clear_bit(bebob->card_index, devices_used); |
@@ -205,7 +216,7 @@ bebob_probe(struct fw_unit *unit, | |||
205 | card->private_free = bebob_card_free; | 216 | card->private_free = bebob_card_free; |
206 | 217 | ||
207 | bebob->card = card; | 218 | bebob->card = card; |
208 | bebob->unit = unit; | 219 | bebob->unit = fw_unit_get(unit); |
209 | bebob->spec = spec; | 220 | bebob->spec = spec; |
210 | mutex_init(&bebob->mutex); | 221 | mutex_init(&bebob->mutex); |
211 | spin_lock_init(&bebob->lock); | 222 | spin_lock_init(&bebob->lock); |
@@ -306,10 +317,11 @@ static void bebob_remove(struct fw_unit *unit) | |||
306 | if (bebob == NULL) | 317 | if (bebob == NULL) |
307 | return; | 318 | return; |
308 | 319 | ||
309 | kfree(bebob->maudio_special_quirk); | 320 | /* Awake bus-reset waiters. */ |
321 | if (!completion_done(&bebob->bus_reset)) | ||
322 | complete_all(&bebob->bus_reset); | ||
310 | 323 | ||
311 | snd_bebob_stream_destroy_duplex(bebob); | 324 | /* No need to wait for releasing card object in this context. */ |
312 | snd_card_disconnect(bebob->card); | ||
313 | snd_card_free_when_closed(bebob->card); | 325 | snd_card_free_when_closed(bebob->card); |
314 | } | 326 | } |
315 | 327 | ||
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c index 0ebcabfdc7ce..98e4fc8121a1 100644 --- a/sound/firewire/bebob/bebob_stream.c +++ b/sound/firewire/bebob/bebob_stream.c | |||
@@ -410,8 +410,6 @@ break_both_connections(struct snd_bebob *bebob) | |||
410 | static void | 410 | static void |
411 | destroy_both_connections(struct snd_bebob *bebob) | 411 | destroy_both_connections(struct snd_bebob *bebob) |
412 | { | 412 | { |
413 | break_both_connections(bebob); | ||
414 | |||
415 | cmp_connection_destroy(&bebob->in_conn); | 413 | cmp_connection_destroy(&bebob->in_conn); |
416 | cmp_connection_destroy(&bebob->out_conn); | 414 | cmp_connection_destroy(&bebob->out_conn); |
417 | } | 415 | } |
@@ -712,22 +710,16 @@ void snd_bebob_stream_update_duplex(struct snd_bebob *bebob) | |||
712 | mutex_unlock(&bebob->mutex); | 710 | mutex_unlock(&bebob->mutex); |
713 | } | 711 | } |
714 | 712 | ||
713 | /* | ||
714 | * This function should be called before starting streams or after stopping | ||
715 | * streams. | ||
716 | */ | ||
715 | void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) | 717 | void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob) |
716 | { | 718 | { |
717 | mutex_lock(&bebob->mutex); | ||
718 | |||
719 | amdtp_stream_pcm_abort(&bebob->rx_stream); | ||
720 | amdtp_stream_pcm_abort(&bebob->tx_stream); | ||
721 | |||
722 | amdtp_stream_stop(&bebob->rx_stream); | ||
723 | amdtp_stream_stop(&bebob->tx_stream); | ||
724 | |||
725 | amdtp_stream_destroy(&bebob->rx_stream); | 719 | amdtp_stream_destroy(&bebob->rx_stream); |
726 | amdtp_stream_destroy(&bebob->tx_stream); | 720 | amdtp_stream_destroy(&bebob->tx_stream); |
727 | 721 | ||
728 | destroy_both_connections(bebob); | 722 | destroy_both_connections(bebob); |
729 | |||
730 | mutex_unlock(&bebob->mutex); | ||
731 | } | 723 | } |
732 | 724 | ||
733 | /* | 725 | /* |
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index fa9cf761b610..07dbd01d7a6b 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c | |||
@@ -311,14 +311,21 @@ end: | |||
311 | return err; | 311 | return err; |
312 | } | 312 | } |
313 | 313 | ||
314 | /* | ||
315 | * This function should be called before starting streams or after stopping | ||
316 | * streams. | ||
317 | */ | ||
314 | static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) | 318 | static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream) |
315 | { | 319 | { |
316 | amdtp_stream_destroy(stream); | 320 | struct fw_iso_resources *resources; |
317 | 321 | ||
318 | if (stream == &dice->tx_stream) | 322 | if (stream == &dice->tx_stream) |
319 | fw_iso_resources_destroy(&dice->tx_resources); | 323 | resources = &dice->tx_resources; |
320 | else | 324 | else |
321 | fw_iso_resources_destroy(&dice->rx_resources); | 325 | resources = &dice->rx_resources; |
326 | |||
327 | amdtp_stream_destroy(stream); | ||
328 | fw_iso_resources_destroy(resources); | ||
322 | } | 329 | } |
323 | 330 | ||
324 | int snd_dice_stream_init_duplex(struct snd_dice *dice) | 331 | int snd_dice_stream_init_duplex(struct snd_dice *dice) |
@@ -332,6 +339,8 @@ int snd_dice_stream_init_duplex(struct snd_dice *dice) | |||
332 | goto end; | 339 | goto end; |
333 | 340 | ||
334 | err = init_stream(dice, &dice->rx_stream); | 341 | err = init_stream(dice, &dice->rx_stream); |
342 | if (err < 0) | ||
343 | destroy_stream(dice, &dice->tx_stream); | ||
335 | end: | 344 | end: |
336 | return err; | 345 | return err; |
337 | } | 346 | } |
@@ -340,10 +349,7 @@ void snd_dice_stream_destroy_duplex(struct snd_dice *dice) | |||
340 | { | 349 | { |
341 | snd_dice_transaction_clear_enable(dice); | 350 | snd_dice_transaction_clear_enable(dice); |
342 | 351 | ||
343 | stop_stream(dice, &dice->tx_stream); | ||
344 | destroy_stream(dice, &dice->tx_stream); | 352 | destroy_stream(dice, &dice->tx_stream); |
345 | |||
346 | stop_stream(dice, &dice->rx_stream); | ||
347 | destroy_stream(dice, &dice->rx_stream); | 353 | destroy_stream(dice, &dice->rx_stream); |
348 | 354 | ||
349 | dice->substreams_counter = 0; | 355 | dice->substreams_counter = 0; |
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 90d8f40ff727..70a111d7f428 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c | |||
@@ -226,11 +226,20 @@ static void dice_card_strings(struct snd_dice *dice) | |||
226 | strcpy(card->mixername, "DICE"); | 226 | strcpy(card->mixername, "DICE"); |
227 | } | 227 | } |
228 | 228 | ||
229 | /* | ||
230 | * This module releases the FireWire unit data after all ALSA character devices | ||
231 | * are released by applications. This is for releasing stream data or finishing | ||
232 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
233 | * references for the unit. | ||
234 | */ | ||
229 | static void dice_card_free(struct snd_card *card) | 235 | static void dice_card_free(struct snd_card *card) |
230 | { | 236 | { |
231 | struct snd_dice *dice = card->private_data; | 237 | struct snd_dice *dice = card->private_data; |
232 | 238 | ||
239 | snd_dice_stream_destroy_duplex(dice); | ||
233 | snd_dice_transaction_destroy(dice); | 240 | snd_dice_transaction_destroy(dice); |
241 | fw_unit_put(dice->unit); | ||
242 | |||
234 | mutex_destroy(&dice->mutex); | 243 | mutex_destroy(&dice->mutex); |
235 | } | 244 | } |
236 | 245 | ||
@@ -251,7 +260,7 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | |||
251 | 260 | ||
252 | dice = card->private_data; | 261 | dice = card->private_data; |
253 | dice->card = card; | 262 | dice->card = card; |
254 | dice->unit = unit; | 263 | dice->unit = fw_unit_get(unit); |
255 | card->private_free = dice_card_free; | 264 | card->private_free = dice_card_free; |
256 | 265 | ||
257 | spin_lock_init(&dice->lock); | 266 | spin_lock_init(&dice->lock); |
@@ -305,10 +314,7 @@ static void dice_remove(struct fw_unit *unit) | |||
305 | { | 314 | { |
306 | struct snd_dice *dice = dev_get_drvdata(&unit->device); | 315 | struct snd_dice *dice = dev_get_drvdata(&unit->device); |
307 | 316 | ||
308 | snd_card_disconnect(dice->card); | 317 | /* No need to wait for releasing card object in this context. */ |
309 | |||
310 | snd_dice_stream_destroy_duplex(dice); | ||
311 | |||
312 | snd_card_free_when_closed(dice->card); | 318 | snd_card_free_when_closed(dice->card); |
313 | } | 319 | } |
314 | 320 | ||
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 3e2ed8e82cbc..2682e7e3e5c9 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c | |||
@@ -173,11 +173,23 @@ end: | |||
173 | return err; | 173 | return err; |
174 | } | 174 | } |
175 | 175 | ||
176 | /* | ||
177 | * This module releases the FireWire unit data after all ALSA character devices | ||
178 | * are released by applications. This is for releasing stream data or finishing | ||
179 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
180 | * references for the unit. | ||
181 | */ | ||
176 | static void | 182 | static void |
177 | efw_card_free(struct snd_card *card) | 183 | efw_card_free(struct snd_card *card) |
178 | { | 184 | { |
179 | struct snd_efw *efw = card->private_data; | 185 | struct snd_efw *efw = card->private_data; |
180 | 186 | ||
187 | snd_efw_stream_destroy_duplex(efw); | ||
188 | snd_efw_transaction_remove_instance(efw); | ||
189 | fw_unit_put(efw->unit); | ||
190 | |||
191 | kfree(efw->resp_buf); | ||
192 | |||
181 | if (efw->card_index >= 0) { | 193 | if (efw->card_index >= 0) { |
182 | mutex_lock(&devices_mutex); | 194 | mutex_lock(&devices_mutex); |
183 | clear_bit(efw->card_index, devices_used); | 195 | clear_bit(efw->card_index, devices_used); |
@@ -185,7 +197,6 @@ efw_card_free(struct snd_card *card) | |||
185 | } | 197 | } |
186 | 198 | ||
187 | mutex_destroy(&efw->mutex); | 199 | mutex_destroy(&efw->mutex); |
188 | kfree(efw->resp_buf); | ||
189 | } | 200 | } |
190 | 201 | ||
191 | static int | 202 | static int |
@@ -218,7 +229,7 @@ efw_probe(struct fw_unit *unit, | |||
218 | card->private_free = efw_card_free; | 229 | card->private_free = efw_card_free; |
219 | 230 | ||
220 | efw->card = card; | 231 | efw->card = card; |
221 | efw->unit = unit; | 232 | efw->unit = fw_unit_get(unit); |
222 | mutex_init(&efw->mutex); | 233 | mutex_init(&efw->mutex); |
223 | spin_lock_init(&efw->lock); | 234 | spin_lock_init(&efw->lock); |
224 | init_waitqueue_head(&efw->hwdep_wait); | 235 | init_waitqueue_head(&efw->hwdep_wait); |
@@ -289,10 +300,7 @@ static void efw_remove(struct fw_unit *unit) | |||
289 | { | 300 | { |
290 | struct snd_efw *efw = dev_get_drvdata(&unit->device); | 301 | struct snd_efw *efw = dev_get_drvdata(&unit->device); |
291 | 302 | ||
292 | snd_efw_stream_destroy_duplex(efw); | 303 | /* No need to wait for releasing card object in this context. */ |
293 | snd_efw_transaction_remove_instance(efw); | ||
294 | |||
295 | snd_card_disconnect(efw->card); | ||
296 | snd_card_free_when_closed(efw->card); | 304 | snd_card_free_when_closed(efw->card); |
297 | } | 305 | } |
298 | 306 | ||
diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 4f440e163667..c55db1bddc80 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c | |||
@@ -100,17 +100,22 @@ end: | |||
100 | return err; | 100 | return err; |
101 | } | 101 | } |
102 | 102 | ||
103 | /* | ||
104 | * This function should be called before starting the stream or after stopping | ||
105 | * the streams. | ||
106 | */ | ||
103 | static void | 107 | static void |
104 | destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) | 108 | destroy_stream(struct snd_efw *efw, struct amdtp_stream *stream) |
105 | { | 109 | { |
106 | stop_stream(efw, stream); | 110 | struct cmp_connection *conn; |
107 | |||
108 | amdtp_stream_destroy(stream); | ||
109 | 111 | ||
110 | if (stream == &efw->tx_stream) | 112 | if (stream == &efw->tx_stream) |
111 | cmp_connection_destroy(&efw->out_conn); | 113 | conn = &efw->out_conn; |
112 | else | 114 | else |
113 | cmp_connection_destroy(&efw->in_conn); | 115 | conn = &efw->in_conn; |
116 | |||
117 | amdtp_stream_destroy(stream); | ||
118 | cmp_connection_destroy(&efw->out_conn); | ||
114 | } | 119 | } |
115 | 120 | ||
116 | static int | 121 | static int |
@@ -319,12 +324,8 @@ void snd_efw_stream_update_duplex(struct snd_efw *efw) | |||
319 | 324 | ||
320 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw) | 325 | void snd_efw_stream_destroy_duplex(struct snd_efw *efw) |
321 | { | 326 | { |
322 | mutex_lock(&efw->mutex); | ||
323 | |||
324 | destroy_stream(efw, &efw->rx_stream); | 327 | destroy_stream(efw, &efw->rx_stream); |
325 | destroy_stream(efw, &efw->tx_stream); | 328 | destroy_stream(efw, &efw->tx_stream); |
326 | |||
327 | mutex_unlock(&efw->mutex); | ||
328 | } | 329 | } |
329 | 330 | ||
330 | void snd_efw_stream_lock_changed(struct snd_efw *efw) | 331 | void snd_efw_stream_lock_changed(struct snd_efw *efw) |
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c index bda845afb470..29ccb3637164 100644 --- a/sound/firewire/oxfw/oxfw-stream.c +++ b/sound/firewire/oxfw/oxfw-stream.c | |||
@@ -337,6 +337,10 @@ void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw, | |||
337 | stop_stream(oxfw, stream); | 337 | stop_stream(oxfw, stream); |
338 | } | 338 | } |
339 | 339 | ||
340 | /* | ||
341 | * This function should be called before starting the stream or after stopping | ||
342 | * the streams. | ||
343 | */ | ||
340 | void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, | 344 | void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, |
341 | struct amdtp_stream *stream) | 345 | struct amdtp_stream *stream) |
342 | { | 346 | { |
@@ -347,8 +351,6 @@ void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw, | |||
347 | else | 351 | else |
348 | conn = &oxfw->in_conn; | 352 | conn = &oxfw->in_conn; |
349 | 353 | ||
350 | stop_stream(oxfw, stream); | ||
351 | |||
352 | amdtp_stream_destroy(stream); | 354 | amdtp_stream_destroy(stream); |
353 | cmp_connection_destroy(conn); | 355 | cmp_connection_destroy(conn); |
354 | } | 356 | } |
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 60e5cad0531a..8c6ce019f437 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c | |||
@@ -104,11 +104,23 @@ end: | |||
104 | return err; | 104 | return err; |
105 | } | 105 | } |
106 | 106 | ||
107 | /* | ||
108 | * This module releases the FireWire unit data after all ALSA character devices | ||
109 | * are released by applications. This is for releasing stream data or finishing | ||
110 | * transactions safely. Thus at returning from .remove(), this module still keep | ||
111 | * references for the unit. | ||
112 | */ | ||
107 | static void oxfw_card_free(struct snd_card *card) | 113 | static void oxfw_card_free(struct snd_card *card) |
108 | { | 114 | { |
109 | struct snd_oxfw *oxfw = card->private_data; | 115 | struct snd_oxfw *oxfw = card->private_data; |
110 | unsigned int i; | 116 | unsigned int i; |
111 | 117 | ||
118 | snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); | ||
119 | if (oxfw->has_output) | ||
120 | snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); | ||
121 | |||
122 | fw_unit_put(oxfw->unit); | ||
123 | |||
112 | for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { | 124 | for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) { |
113 | kfree(oxfw->tx_stream_formats[i]); | 125 | kfree(oxfw->tx_stream_formats[i]); |
114 | kfree(oxfw->rx_stream_formats[i]); | 126 | kfree(oxfw->rx_stream_formats[i]); |
@@ -136,7 +148,7 @@ static int oxfw_probe(struct fw_unit *unit, | |||
136 | oxfw = card->private_data; | 148 | oxfw = card->private_data; |
137 | oxfw->card = card; | 149 | oxfw->card = card; |
138 | mutex_init(&oxfw->mutex); | 150 | mutex_init(&oxfw->mutex); |
139 | oxfw->unit = unit; | 151 | oxfw->unit = fw_unit_get(unit); |
140 | oxfw->device_info = (const struct device_info *)id->driver_data; | 152 | oxfw->device_info = (const struct device_info *)id->driver_data; |
141 | spin_lock_init(&oxfw->lock); | 153 | spin_lock_init(&oxfw->lock); |
142 | init_waitqueue_head(&oxfw->hwdep_wait); | 154 | init_waitqueue_head(&oxfw->hwdep_wait); |
@@ -212,12 +224,7 @@ static void oxfw_remove(struct fw_unit *unit) | |||
212 | { | 224 | { |
213 | struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); | 225 | struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device); |
214 | 226 | ||
215 | snd_card_disconnect(oxfw->card); | 227 | /* No need to wait for releasing card object in this context. */ |
216 | |||
217 | snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream); | ||
218 | if (oxfw->has_output) | ||
219 | snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream); | ||
220 | |||
221 | snd_card_free_when_closed(oxfw->card); | 228 | snd_card_free_when_closed(oxfw->card); |
222 | } | 229 | } |
223 | 230 | ||