diff options
-rw-r--r-- | Documentation/sound/alsa/Procfile.txt | 13 | ||||
-rw-r--r-- | sound/core/Makefile | 3 | ||||
-rw-r--r-- | sound/core/pcm_lib.c | 146 | ||||
-rw-r--r-- | sound/core/pcm_trace.h | 110 |
4 files changed, 137 insertions, 135 deletions
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt index 7fcd1ad96fcc..cfc49567b9dc 100644 --- a/Documentation/sound/alsa/Procfile.txt +++ b/Documentation/sound/alsa/Procfile.txt | |||
@@ -101,10 +101,6 @@ card*/pcm*/xrun_debug | |||
101 | bit 0 = Enable XRUN/jiffies debug messages | 101 | bit 0 = Enable XRUN/jiffies debug messages |
102 | bit 1 = Show stack trace at XRUN / jiffies check | 102 | bit 1 = Show stack trace at XRUN / jiffies check |
103 | bit 2 = Enable additional jiffies check | 103 | bit 2 = Enable additional jiffies check |
104 | bit 3 = Log hwptr update at each period interrupt | ||
105 | bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr() | ||
106 | bit 5 = Show last 10 positions on error | ||
107 | bit 6 = Do above only once | ||
108 | 104 | ||
109 | When the bit 0 is set, the driver will show the messages to | 105 | When the bit 0 is set, the driver will show the messages to |
110 | kernel log when an xrun is detected. The debug message is | 106 | kernel log when an xrun is detected. The debug message is |
@@ -121,15 +117,6 @@ card*/pcm*/xrun_debug | |||
121 | buggy) hardware that doesn't give smooth pointer updates. | 117 | buggy) hardware that doesn't give smooth pointer updates. |
122 | This feature is enabled via the bit 2. | 118 | This feature is enabled via the bit 2. |
123 | 119 | ||
124 | Bits 3 and 4 are for logging the hwptr records. Note that | ||
125 | these will give flood of kernel messages. | ||
126 | |||
127 | When bit 5 is set, the driver logs the last 10 xrun errors and | ||
128 | the proc file shows each jiffies, position, period_size, | ||
129 | buffer_size, old_hw_ptr, and hw_ptr_base values. | ||
130 | |||
131 | When bit 6 is set, the full xrun log is shown only once. | ||
132 | |||
133 | card*/pcm*/sub*/info | 120 | card*/pcm*/sub*/info |
134 | The general information of this PCM sub-stream. | 121 | The general information of this PCM sub-stream. |
135 | 122 | ||
diff --git a/sound/core/Makefile b/sound/core/Makefile index 394a38909f6b..4daf2f58261c 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ | |||
14 | pcm_memory.o memalloc.o | 14 | pcm_memory.o memalloc.o |
15 | snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o | 15 | snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o |
16 | 16 | ||
17 | # for trace-points | ||
18 | CFLAGS_pcm_lib.o := -I$(src) | ||
19 | |||
17 | snd-pcm-dmaengine-objs := pcm_dmaengine.o | 20 | snd-pcm-dmaengine-objs := pcm_dmaengine.o |
18 | 21 | ||
19 | snd-rawmidi-objs := rawmidi.o | 22 | snd-rawmidi-objs := rawmidi.o |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 7b9e2fb35a86..ec9e7866177f 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -32,6 +32,15 @@ | |||
32 | #include <sound/pcm_params.h> | 32 | #include <sound/pcm_params.h> |
33 | #include <sound/timer.h> | 33 | #include <sound/timer.h> |
34 | 34 | ||
35 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
36 | #define CREATE_TRACE_POINTS | ||
37 | #include "pcm_trace.h" | ||
38 | #else | ||
39 | #define trace_hwptr(substream, pos, in_interrupt) | ||
40 | #define trace_xrun(substream) | ||
41 | #define trace_hw_ptr_error(substream, reason) | ||
42 | #endif | ||
43 | |||
35 | /* | 44 | /* |
36 | * fill ring buffer with silence | 45 | * fill ring buffer with silence |
37 | * runtime->silence_start: starting pointer to silence area | 46 | * runtime->silence_start: starting pointer to silence area |
@@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name); | |||
146 | #define XRUN_DEBUG_BASIC (1<<0) | 155 | #define XRUN_DEBUG_BASIC (1<<0) |
147 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ | 156 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ |
148 | #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ | 157 | #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ |
149 | #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ | ||
150 | #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ | ||
151 | #define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ | ||
152 | #define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ | ||
153 | 158 | ||
154 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 159 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
155 | 160 | ||
@@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream) | |||
168 | { | 173 | { |
169 | struct snd_pcm_runtime *runtime = substream->runtime; | 174 | struct snd_pcm_runtime *runtime = substream->runtime; |
170 | 175 | ||
176 | trace_xrun(substream); | ||
171 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 177 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
172 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 178 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
173 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 179 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
@@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream) | |||
180 | } | 186 | } |
181 | 187 | ||
182 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 188 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
183 | #define hw_ptr_error(substream, fmt, args...) \ | 189 | #define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \ |
184 | do { \ | 190 | do { \ |
191 | trace_hw_ptr_error(substream, reason); \ | ||
185 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ | 192 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ |
186 | xrun_log_show(substream); \ | 193 | pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \ |
187 | pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \ | 194 | (in_interrupt) ? 'Q' : 'P', ##args); \ |
188 | dump_stack_on_xrun(substream); \ | 195 | dump_stack_on_xrun(substream); \ |
189 | } \ | 196 | } \ |
190 | } while (0) | 197 | } while (0) |
191 | 198 | ||
192 | #define XRUN_LOG_CNT 10 | ||
193 | |||
194 | struct hwptr_log_entry { | ||
195 | unsigned int in_interrupt; | ||
196 | unsigned long jiffies; | ||
197 | snd_pcm_uframes_t pos; | ||
198 | snd_pcm_uframes_t period_size; | ||
199 | snd_pcm_uframes_t buffer_size; | ||
200 | snd_pcm_uframes_t old_hw_ptr; | ||
201 | snd_pcm_uframes_t hw_ptr_base; | ||
202 | }; | ||
203 | |||
204 | struct snd_pcm_hwptr_log { | ||
205 | unsigned int idx; | ||
206 | unsigned int hit: 1; | ||
207 | struct hwptr_log_entry entries[XRUN_LOG_CNT]; | ||
208 | }; | ||
209 | |||
210 | static void xrun_log(struct snd_pcm_substream *substream, | ||
211 | snd_pcm_uframes_t pos, int in_interrupt) | ||
212 | { | ||
213 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
214 | struct snd_pcm_hwptr_log *log = runtime->hwptr_log; | ||
215 | struct hwptr_log_entry *entry; | ||
216 | |||
217 | if (log == NULL) { | ||
218 | log = kzalloc(sizeof(*log), GFP_ATOMIC); | ||
219 | if (log == NULL) | ||
220 | return; | ||
221 | runtime->hwptr_log = log; | ||
222 | } else { | ||
223 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
224 | return; | ||
225 | } | ||
226 | entry = &log->entries[log->idx]; | ||
227 | entry->in_interrupt = in_interrupt; | ||
228 | entry->jiffies = jiffies; | ||
229 | entry->pos = pos; | ||
230 | entry->period_size = runtime->period_size; | ||
231 | entry->buffer_size = runtime->buffer_size; | ||
232 | entry->old_hw_ptr = runtime->status->hw_ptr; | ||
233 | entry->hw_ptr_base = runtime->hw_ptr_base; | ||
234 | log->idx = (log->idx + 1) % XRUN_LOG_CNT; | ||
235 | } | ||
236 | |||
237 | static void xrun_log_show(struct snd_pcm_substream *substream) | ||
238 | { | ||
239 | struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; | ||
240 | struct hwptr_log_entry *entry; | ||
241 | char name[16]; | ||
242 | unsigned int idx; | ||
243 | int cnt; | ||
244 | |||
245 | if (log == NULL) | ||
246 | return; | ||
247 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
248 | return; | ||
249 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
250 | for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { | ||
251 | entry = &log->entries[idx]; | ||
252 | if (entry->period_size == 0) | ||
253 | break; | ||
254 | pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, " | ||
255 | "hwptr=%ld/%ld\n", | ||
256 | name, entry->in_interrupt ? "[Q] " : "", | ||
257 | entry->jiffies, | ||
258 | (unsigned long)entry->pos, | ||
259 | (unsigned long)entry->period_size, | ||
260 | (unsigned long)entry->buffer_size, | ||
261 | (unsigned long)entry->old_hw_ptr, | ||
262 | (unsigned long)entry->hw_ptr_base); | ||
263 | idx++; | ||
264 | idx %= XRUN_LOG_CNT; | ||
265 | } | ||
266 | log->hit = 1; | ||
267 | } | ||
268 | |||
269 | #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ | 199 | #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ |
270 | 200 | ||
271 | #define hw_ptr_error(substream, fmt, args...) do { } while (0) | 201 | #define hw_ptr_error(substream, fmt, args...) do { } while (0) |
272 | #define xrun_log(substream, pos, in_interrupt) do { } while (0) | ||
273 | #define xrun_log_show(substream) do { } while (0) | ||
274 | 202 | ||
275 | #endif | 203 | #endif |
276 | 204 | ||
@@ -343,7 +271,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
343 | if (printk_ratelimit()) { | 271 | if (printk_ratelimit()) { |
344 | char name[16]; | 272 | char name[16]; |
345 | snd_pcm_debug_name(substream, name, sizeof(name)); | 273 | snd_pcm_debug_name(substream, name, sizeof(name)); |
346 | xrun_log_show(substream); | ||
347 | pcm_err(substream->pcm, | 274 | pcm_err(substream->pcm, |
348 | "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", | 275 | "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n", |
349 | name, pos, runtime->buffer_size, | 276 | name, pos, runtime->buffer_size, |
@@ -352,8 +279,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
352 | pos = 0; | 279 | pos = 0; |
353 | } | 280 | } |
354 | pos -= pos % runtime->min_align; | 281 | pos -= pos % runtime->min_align; |
355 | if (xrun_debug(substream, XRUN_DEBUG_LOG)) | 282 | trace_hwptr(substream, pos, in_interrupt); |
356 | xrun_log(substream, pos, in_interrupt); | ||
357 | hw_base = runtime->hw_ptr_base; | 283 | hw_base = runtime->hw_ptr_base; |
358 | new_hw_ptr = hw_base + pos; | 284 | new_hw_ptr = hw_base + pos; |
359 | if (in_interrupt) { | 285 | if (in_interrupt) { |
@@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
388 | delta = new_hw_ptr - old_hw_ptr; | 314 | delta = new_hw_ptr - old_hw_ptr; |
389 | if (delta < 0) | 315 | if (delta < 0) |
390 | delta += runtime->boundary; | 316 | delta += runtime->boundary; |
391 | if (xrun_debug(substream, in_interrupt ? | ||
392 | XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { | ||
393 | char name[16]; | ||
394 | snd_pcm_debug_name(substream, name, sizeof(name)); | ||
395 | pcm_dbg(substream->pcm, | ||
396 | "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n", | ||
397 | in_interrupt ? "period" : "hwptr", | ||
398 | name, | ||
399 | (unsigned int)pos, | ||
400 | (unsigned int)runtime->period_size, | ||
401 | (unsigned int)runtime->buffer_size, | ||
402 | (unsigned long)delta, | ||
403 | (unsigned long)old_hw_ptr, | ||
404 | (unsigned long)new_hw_ptr, | ||
405 | (unsigned long)runtime->hw_ptr_base); | ||
406 | } | ||
407 | 317 | ||
408 | if (runtime->no_period_wakeup) { | 318 | if (runtime->no_period_wakeup) { |
409 | snd_pcm_sframes_t xrun_threshold; | 319 | snd_pcm_sframes_t xrun_threshold; |
@@ -431,13 +341,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
431 | 341 | ||
432 | /* something must be really wrong */ | 342 | /* something must be really wrong */ |
433 | if (delta >= runtime->buffer_size + runtime->period_size) { | 343 | if (delta >= runtime->buffer_size + runtime->period_size) { |
434 | hw_ptr_error(substream, | 344 | hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr", |
435 | "Unexpected hw_pointer value %s" | 345 | "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", |
436 | "(stream=%i, pos=%ld, new_hw_ptr=%ld, " | 346 | substream->stream, (long)pos, |
437 | "old_hw_ptr=%ld)\n", | 347 | (long)new_hw_ptr, (long)old_hw_ptr); |
438 | in_interrupt ? "[Q] " : "[P]", | ||
439 | substream->stream, (long)pos, | ||
440 | (long)new_hw_ptr, (long)old_hw_ptr); | ||
441 | return 0; | 348 | return 0; |
442 | } | 349 | } |
443 | 350 | ||
@@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
474 | delta--; | 381 | delta--; |
475 | } | 382 | } |
476 | /* align hw_base to buffer_size */ | 383 | /* align hw_base to buffer_size */ |
477 | hw_ptr_error(substream, | 384 | hw_ptr_error(substream, in_interrupt, "hw_ptr skipping", |
478 | "hw_ptr skipping! %s" | 385 | "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", |
479 | "(pos=%ld, delta=%ld, period=%ld, " | ||
480 | "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", | ||
481 | in_interrupt ? "[Q] " : "", | ||
482 | (long)pos, (long)hdelta, | 386 | (long)pos, (long)hdelta, |
483 | (long)runtime->period_size, jdelta, | 387 | (long)runtime->period_size, jdelta, |
484 | ((hdelta * HZ) / runtime->rate), hw_base, | 388 | ((hdelta * HZ) / runtime->rate), hw_base, |
@@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, | |||
490 | } | 394 | } |
491 | no_jiffies_check: | 395 | no_jiffies_check: |
492 | if (delta > runtime->period_size + runtime->period_size / 2) { | 396 | if (delta > runtime->period_size + runtime->period_size / 2) { |
493 | hw_ptr_error(substream, | 397 | hw_ptr_error(substream, in_interrupt, |
494 | "Lost interrupts? %s" | 398 | "Lost interrupts?", |
495 | "(stream=%i, delta=%ld, new_hw_ptr=%ld, " | 399 | "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n", |
496 | "old_hw_ptr=%ld)\n", | ||
497 | in_interrupt ? "[Q] " : "", | ||
498 | substream->stream, (long)delta, | 400 | substream->stream, (long)delta, |
499 | (long)new_hw_ptr, | 401 | (long)new_hw_ptr, |
500 | (long)old_hw_ptr); | 402 | (long)old_hw_ptr); |
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h new file mode 100644 index 000000000000..b63b654da5ff --- /dev/null +++ b/sound/core/pcm_trace.h | |||
@@ -0,0 +1,110 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM snd_pcm | ||
3 | #define TRACE_INCLUDE_FILE pcm_trace | ||
4 | |||
5 | #if !defined(_PCM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) | ||
6 | #define _PCM_TRACE_H | ||
7 | |||
8 | #include <linux/tracepoint.h> | ||
9 | |||
10 | TRACE_EVENT(hwptr, | ||
11 | TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, bool irq), | ||
12 | TP_ARGS(substream, pos, irq), | ||
13 | TP_STRUCT__entry( | ||
14 | __field( bool, in_interrupt ) | ||
15 | __field( unsigned int, card ) | ||
16 | __field( unsigned int, device ) | ||
17 | __field( unsigned int, number ) | ||
18 | __field( unsigned int, stream ) | ||
19 | __field( snd_pcm_uframes_t, pos ) | ||
20 | __field( snd_pcm_uframes_t, period_size ) | ||
21 | __field( snd_pcm_uframes_t, buffer_size ) | ||
22 | __field( snd_pcm_uframes_t, old_hw_ptr ) | ||
23 | __field( snd_pcm_uframes_t, hw_ptr_base ) | ||
24 | ), | ||
25 | TP_fast_assign( | ||
26 | __entry->in_interrupt = (irq); | ||
27 | __entry->card = (substream)->pcm->card->number; | ||
28 | __entry->device = (substream)->pcm->device; | ||
29 | __entry->number = (substream)->number; | ||
30 | __entry->stream = (substream)->stream; | ||
31 | __entry->pos = (pos); | ||
32 | __entry->period_size = (substream)->runtime->period_size; | ||
33 | __entry->buffer_size = (substream)->runtime->buffer_size; | ||
34 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; | ||
35 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; | ||
36 | ), | ||
37 | TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu", | ||
38 | __entry->card, __entry->device, | ||
39 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | ||
40 | __entry->number, | ||
41 | __entry->in_interrupt ? "IRQ" : "POS", | ||
42 | (unsigned long)__entry->pos, | ||
43 | (unsigned long)__entry->old_hw_ptr, | ||
44 | (unsigned long)__entry->hw_ptr_base, | ||
45 | (unsigned long)__entry->period_size, | ||
46 | (unsigned long)__entry->buffer_size) | ||
47 | ); | ||
48 | |||
49 | TRACE_EVENT(xrun, | ||
50 | TP_PROTO(struct snd_pcm_substream *substream), | ||
51 | TP_ARGS(substream), | ||
52 | TP_STRUCT__entry( | ||
53 | __field( unsigned int, card ) | ||
54 | __field( unsigned int, device ) | ||
55 | __field( unsigned int, number ) | ||
56 | __field( unsigned int, stream ) | ||
57 | __field( snd_pcm_uframes_t, period_size ) | ||
58 | __field( snd_pcm_uframes_t, buffer_size ) | ||
59 | __field( snd_pcm_uframes_t, old_hw_ptr ) | ||
60 | __field( snd_pcm_uframes_t, hw_ptr_base ) | ||
61 | ), | ||
62 | TP_fast_assign( | ||
63 | __entry->card = (substream)->pcm->card->number; | ||
64 | __entry->device = (substream)->pcm->device; | ||
65 | __entry->number = (substream)->number; | ||
66 | __entry->stream = (substream)->stream; | ||
67 | __entry->period_size = (substream)->runtime->period_size; | ||
68 | __entry->buffer_size = (substream)->runtime->buffer_size; | ||
69 | __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr; | ||
70 | __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base; | ||
71 | ), | ||
72 | TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu", | ||
73 | __entry->card, __entry->device, | ||
74 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | ||
75 | __entry->number, | ||
76 | (unsigned long)__entry->old_hw_ptr, | ||
77 | (unsigned long)__entry->hw_ptr_base, | ||
78 | (unsigned long)__entry->period_size, | ||
79 | (unsigned long)__entry->buffer_size) | ||
80 | ); | ||
81 | |||
82 | TRACE_EVENT(hw_ptr_error, | ||
83 | TP_PROTO(struct snd_pcm_substream *substream, const char *why), | ||
84 | TP_ARGS(substream, why), | ||
85 | TP_STRUCT__entry( | ||
86 | __field( unsigned int, card ) | ||
87 | __field( unsigned int, device ) | ||
88 | __field( unsigned int, number ) | ||
89 | __field( unsigned int, stream ) | ||
90 | __field( const char *, reason ) | ||
91 | ), | ||
92 | TP_fast_assign( | ||
93 | __entry->card = (substream)->pcm->card->number; | ||
94 | __entry->device = (substream)->pcm->device; | ||
95 | __entry->number = (substream)->number; | ||
96 | __entry->stream = (substream)->stream; | ||
97 | __entry->reason = (why); | ||
98 | ), | ||
99 | TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s", | ||
100 | __entry->card, __entry->device, | ||
101 | __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c', | ||
102 | __entry->number, __entry->reason) | ||
103 | ); | ||
104 | |||
105 | #endif /* _PCM_TRACE_H */ | ||
106 | |||
107 | /* This part must be outside protection */ | ||
108 | #undef TRACE_INCLUDE_PATH | ||
109 | #define TRACE_INCLUDE_PATH . | ||
110 | #include <trace/define_trace.h> | ||