aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/amdtp.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2012-05-13 16:03:09 -0400
committerTakashi Iwai <tiwai@suse.de>2012-05-14 04:43:30 -0400
commit76fb87894828756e069a43ce55f775a6c893a53d (patch)
tree270c4ca71a84ace95f7aef751477427365f395e3 /sound/firewire/amdtp.c
parent7df4a691fb6645405c9d3dad8d27f8e5e3451e00 (diff)
ALSA: firewire-lib: taskletize the snd_pcm_period_elapsed() call
The following patch might introduce this call chain: PCM .pointer callback + fw_iso_context_flush_completions + packet callback + snd_pcm_period_elapsed + PCM .pointer callback Recursive calls to the pointer callback are not possible due to the PCM group locking, so avoid this by moving the period notification into a separate tasklet. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/amdtp.c')
-rw-r--r--sound/firewire/amdtp.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 87657dd7714c..3284ee9c1eca 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -31,6 +31,8 @@
31#define INTERRUPT_INTERVAL 16 31#define INTERRUPT_INTERVAL 16
32#define QUEUE_LENGTH 48 32#define QUEUE_LENGTH 48
33 33
34static void pcm_period_tasklet(unsigned long data);
35
34/** 36/**
35 * amdtp_out_stream_init - initialize an AMDTP output stream structure 37 * amdtp_out_stream_init - initialize an AMDTP output stream structure
36 * @s: the AMDTP output stream to initialize 38 * @s: the AMDTP output stream to initialize
@@ -47,6 +49,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
47 s->flags = flags; 49 s->flags = flags;
48 s->context = ERR_PTR(-1); 50 s->context = ERR_PTR(-1);
49 mutex_init(&s->mutex); 51 mutex_init(&s->mutex);
52 tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
50 s->packet_index = 0; 53 s->packet_index = 0;
51 54
52 return 0; 55 return 0;
@@ -164,6 +167,20 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
164} 167}
165EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format); 168EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);
166 169
170/**
171 * amdtp_out_stream_pcm_prepare - prepare PCM device for running
172 * @s: the AMDTP output stream
173 *
174 * This function should be called from the PCM device's .prepare callback.
175 */
176void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
177{
178 tasklet_kill(&s->period_tasklet);
179 s->pcm_buffer_pointer = 0;
180 s->pcm_period_pointer = 0;
181}
182EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare);
183
167static unsigned int calculate_data_blocks(struct amdtp_out_stream *s) 184static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
168{ 185{
169 unsigned int phase, data_blocks; 186 unsigned int phase, data_blocks;
@@ -376,11 +393,20 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
376 s->pcm_period_pointer += data_blocks; 393 s->pcm_period_pointer += data_blocks;
377 if (s->pcm_period_pointer >= pcm->runtime->period_size) { 394 if (s->pcm_period_pointer >= pcm->runtime->period_size) {
378 s->pcm_period_pointer -= pcm->runtime->period_size; 395 s->pcm_period_pointer -= pcm->runtime->period_size;
379 snd_pcm_period_elapsed(pcm); 396 tasklet_hi_schedule(&s->period_tasklet);
380 } 397 }
381 } 398 }
382} 399}
383 400
401static void pcm_period_tasklet(unsigned long data)
402{
403 struct amdtp_out_stream *s = (void *)data;
404 struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
405
406 if (pcm)
407 snd_pcm_period_elapsed(pcm);
408}
409
384static void out_packet_callback(struct fw_iso_context *context, u32 cycle, 410static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
385 size_t header_length, void *header, void *data) 411 size_t header_length, void *header, void *data)
386{ 412{
@@ -532,6 +558,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s)
532 return; 558 return;
533 } 559 }
534 560
561 tasklet_kill(&s->period_tasklet);
535 fw_iso_context_stop(s->context); 562 fw_iso_context_stop(s->context);
536 fw_iso_context_destroy(s->context); 563 fw_iso_context_destroy(s->context);
537 s->context = ERR_PTR(-1); 564 s->context = ERR_PTR(-1);