diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-11-04 08:02:40 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-11-04 08:09:16 -0500 |
commit | 2b30d411dbc6eddfb5b4f9afd5a2c57b6f4dd96c (patch) | |
tree | 02f9efaa6a39b5579eb3f708435ef743b2ab4d09 | |
parent | f5914908a5b7b2338f210e56827a1ef35585dc6d (diff) |
ALSA: pcm: Add xrun_injection proc entry
This patch adds a new proc entry for PCM substreams to inject an
XRUN. When a PCM substream is running and any value is written to its
xrun_injection proc file, the driver triggers XRUN. This is a useful
feature for debugging XRUN and error handling code paths.
Note that this entry is enabled only when CONFIG_SND_PCM_XRUN_DEBUG is
set.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | Documentation/sound/alsa/Procfile.txt | 4 | ||||
-rw-r--r-- | include/sound/pcm.h | 3 | ||||
-rw-r--r-- | sound/core/pcm.c | 33 |
3 files changed, 40 insertions, 0 deletions
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index cfc49567b9dc..7f8a0d325905 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt | |||
@@ -133,6 +133,10 @@ card*/pcm*/sub*/sw_params | |||
133 | card*/pcm*/sub*/prealloc | 133 | card*/pcm*/sub*/prealloc |
134 | The buffer pre-allocation information. | 134 | The buffer pre-allocation information. |
135 | 135 | ||
136 | card*/pcm*/sub*/xrun_injection | ||
137 | Triggers an XRUN to the running stream when any value is | ||
138 | written to this proc file. Used for fault injection. | ||
139 | This entry is write-only. | ||
136 | 140 | ||
137 | AC97 Codec Information | 141 | AC97 Codec Information |
138 | ---------------------- | 142 | ---------------------- |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 29eb09ef2969..0b8daeed0a33 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -416,7 +416,10 @@ struct snd_pcm_substream { | |||
416 | struct snd_info_entry *proc_status_entry; | 416 | struct snd_info_entry *proc_status_entry; |
417 | struct snd_info_entry *proc_prealloc_entry; | 417 | struct snd_info_entry *proc_prealloc_entry; |
418 | struct snd_info_entry *proc_prealloc_max_entry; | 418 | struct snd_info_entry *proc_prealloc_max_entry; |
419 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
420 | struct snd_info_entry *proc_xrun_injection_entry; | ||
419 | #endif | 421 | #endif |
422 | #endif /* CONFIG_SND_VERBOSE_PROCFS */ | ||
420 | /* misc flags */ | 423 | /* misc flags */ |
421 | unsigned int hw_opened: 1; | 424 | unsigned int hw_opened: 1; |
422 | }; | 425 | }; |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 31acc3df62cd..8f624b7af0ca 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -483,6 +483,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, | |||
483 | } | 483 | } |
484 | 484 | ||
485 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 485 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
486 | static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry, | ||
487 | struct snd_info_buffer *buffer) | ||
488 | { | ||
489 | struct snd_pcm_substream *substream = entry->private_data; | ||
490 | struct snd_pcm_runtime *runtime; | ||
491 | |||
492 | snd_pcm_stream_lock_irq(substream); | ||
493 | runtime = substream->runtime; | ||
494 | if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING) | ||
495 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
496 | snd_pcm_stream_unlock_irq(substream); | ||
497 | } | ||
498 | |||
486 | static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, | 499 | static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry, |
487 | struct snd_info_buffer *buffer) | 500 | struct snd_info_buffer *buffer) |
488 | { | 501 | { |
@@ -614,6 +627,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
614 | } | 627 | } |
615 | substream->proc_status_entry = entry; | 628 | substream->proc_status_entry = entry; |
616 | 629 | ||
630 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
631 | entry = snd_info_create_card_entry(card, "xrun_injection", | ||
632 | substream->proc_root); | ||
633 | if (entry) { | ||
634 | entry->private_data = substream; | ||
635 | entry->c.text.read = NULL; | ||
636 | entry->c.text.write = snd_pcm_xrun_injection_write; | ||
637 | entry->mode = S_IFREG | S_IWUSR; | ||
638 | if (snd_info_register(entry) < 0) { | ||
639 | snd_info_free_entry(entry); | ||
640 | entry = NULL; | ||
641 | } | ||
642 | } | ||
643 | substream->proc_xrun_injection_entry = entry; | ||
644 | #endif /* CONFIG_SND_PCM_XRUN_DEBUG */ | ||
645 | |||
617 | return 0; | 646 | return 0; |
618 | } | 647 | } |
619 | 648 | ||
@@ -627,6 +656,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) | |||
627 | substream->proc_sw_params_entry = NULL; | 656 | substream->proc_sw_params_entry = NULL; |
628 | snd_info_free_entry(substream->proc_status_entry); | 657 | snd_info_free_entry(substream->proc_status_entry); |
629 | substream->proc_status_entry = NULL; | 658 | substream->proc_status_entry = NULL; |
659 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
660 | snd_info_free_entry(substream->proc_xrun_injection_entry); | ||
661 | substream->proc_xrun_injection_entry = NULL; | ||
662 | #endif | ||
630 | snd_info_free_entry(substream->proc_root); | 663 | snd_info_free_entry(substream->proc_root); |
631 | substream->proc_root = NULL; | 664 | substream->proc_root = NULL; |
632 | return 0; | 665 | return 0; |