This source file includes following definitions.
- snd_pcm_indirect2_stat
- snd_pcm_indirect2_increase_min_periods
- snd_pcm_indirect2_pointer
- snd_pcm_indirect2_playback_transfer
- snd_pcm_indirect2_playback_interrupt
- snd_pcm_indirect2_capture_transfer
- snd_pcm_indirect2_capture_interrupt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 #include <sound/core.h>
17
18
19 #include <sound/pcm.h>
20
21 #include "pcm-indirect2.h"
22
23 #ifdef SND_PCM_INDIRECT2_STAT
24
25 #include <linux/jiffies.h>
26
27 void snd_pcm_indirect2_stat(struct snd_pcm_substream *substream,
28 struct snd_pcm_indirect2 *rec)
29 {
30 struct snd_pcm_runtime *runtime = substream->runtime;
31 int i;
32 int j;
33 int k;
34 int seconds = (rec->lastbytetime - rec->firstbytetime) / HZ;
35
36 snd_printk(KERN_DEBUG "STAT: mul_elapsed: %u, mul_elapsed_real: %d, "
37 "irq_occurred: %d\n",
38 rec->mul_elapsed, rec->mul_elapsed_real, rec->irq_occured);
39 snd_printk(KERN_DEBUG "STAT: min_multiple: %d (irqs/period)\n",
40 rec->min_multiple);
41 snd_printk(KERN_DEBUG "STAT: firstbytetime: %lu, lastbytetime: %lu, "
42 "firstzerotime: %lu\n",
43 rec->firstbytetime, rec->lastbytetime, rec->firstzerotime);
44 snd_printk(KERN_DEBUG "STAT: bytes2hw: %u Bytes => (by runtime->rate) "
45 "length: %d s\n",
46 rec->bytes2hw, rec->bytes2hw / 2 / 2 / runtime->rate);
47 snd_printk(KERN_DEBUG "STAT: (by measurement) length: %d => "
48 "rate: %d Bytes/s = %d Frames/s|Hz\n",
49 seconds, rec->bytes2hw / seconds,
50 rec->bytes2hw / 2 / 2 / seconds);
51 snd_printk(KERN_DEBUG
52 "STAT: zeros2hw: %u = %d ms ~ %d * %d zero copies\n",
53 rec->zeros2hw, ((rec->zeros2hw / 2 / 2) * 1000) /
54 runtime->rate,
55 rec->zeros2hw / (rec->hw_buffer_size / 2),
56 (rec->hw_buffer_size / 2));
57 snd_printk(KERN_DEBUG "STAT: pointer_calls: %u, lastdifftime: %u\n",
58 rec->pointer_calls, rec->lastdifftime);
59 snd_printk(KERN_DEBUG "STAT: sw_io: %d, sw_data: %d\n", rec->sw_io,
60 rec->sw_data);
61 snd_printk(KERN_DEBUG "STAT: byte_sizes[]:\n");
62 k = 0;
63 for (j = 0; j < 8; j++) {
64 for (i = j * 8; i < (j + 1) * 8; i++)
65 if (rec->byte_sizes[i] != 0) {
66 snd_printk(KERN_DEBUG "%u: %u",
67 i, rec->byte_sizes[i]);
68 k++;
69 }
70 if (((k % 8) == 0) && (k != 0)) {
71 snd_printk(KERN_DEBUG "\n");
72 k = 0;
73 }
74 }
75 snd_printk(KERN_DEBUG "\n");
76 snd_printk(KERN_DEBUG "STAT: zero_sizes[]:\n");
77 for (j = 0; j < 8; j++) {
78 k = 0;
79 for (i = j * 8; i < (j + 1) * 8; i++)
80 if (rec->zero_sizes[i] != 0)
81 snd_printk(KERN_DEBUG "%u: %u",
82 i, rec->zero_sizes[i]);
83 else
84 k++;
85 if (!k)
86 snd_printk(KERN_DEBUG "\n");
87 }
88 snd_printk(KERN_DEBUG "\n");
89 snd_printk(KERN_DEBUG "STAT: min_adds[]:\n");
90 for (j = 0; j < 8; j++) {
91 if (rec->min_adds[j] != 0)
92 snd_printk(KERN_DEBUG "%u: %u", j, rec->min_adds[j]);
93 }
94 snd_printk(KERN_DEBUG "\n");
95 snd_printk(KERN_DEBUG "STAT: mul_adds[]:\n");
96 for (j = 0; j < 8; j++) {
97 if (rec->mul_adds[j] != 0)
98 snd_printk(KERN_DEBUG "%u: %u", j, rec->mul_adds[j]);
99 }
100 snd_printk(KERN_DEBUG "\n");
101 snd_printk(KERN_DEBUG
102 "STAT: zero_times_saved: %d, zero_times_notsaved: %d\n",
103 rec->zero_times_saved, rec->zero_times_notsaved);
104
105
106
107
108
109
110
111
112
113
114
115 return;
116 }
117 #endif
118
119
120
121
122 static void
123 snd_pcm_indirect2_increase_min_periods(struct snd_pcm_substream *substream,
124 struct snd_pcm_indirect2 *rec,
125 int isplay, int iscopy,
126 unsigned int bytes)
127 {
128 if (rec->min_periods >= 0) {
129 if (iscopy) {
130 rec->sw_io += bytes;
131 if (rec->sw_io >= rec->sw_buffer_size)
132 rec->sw_io -= rec->sw_buffer_size;
133 } else if (isplay) {
134
135
136
137
138
139 if (!rec->check_alignment) {
140 if (rec->bytes2hw %
141 snd_pcm_lib_period_bytes(substream)) {
142 unsigned bytes2hw_aligned =
143 (1 +
144 (rec->bytes2hw /
145 snd_pcm_lib_period_bytes
146 (substream))) *
147 snd_pcm_lib_period_bytes
148 (substream);
149 rec->sw_data =
150 bytes2hw_aligned %
151 rec->sw_buffer_size;
152 #ifdef SND_PCM_INDIRECT2_STAT
153 snd_printk(KERN_DEBUG
154 "STAT: @re-align: aligned "
155 "bytes2hw to next period "
156 "size boundary: %d "
157 "(instead of %d)\n",
158 bytes2hw_aligned,
159 rec->bytes2hw);
160 snd_printk(KERN_DEBUG
161 "STAT: @re-align: sw_data "
162 "moves to: %d\n",
163 rec->sw_data);
164 #endif
165 }
166 rec->check_alignment = 1;
167 }
168
169
170
171
172
173
174 if (rec->sw_io != rec->sw_data) {
175 unsigned int diff;
176 if (rec->sw_data > rec->sw_io)
177 diff = rec->sw_data - rec->sw_io;
178 else
179 diff = (rec->sw_buffer_size -
180 rec->sw_io) +
181 rec->sw_data;
182 if (bytes >= diff)
183 rec->sw_io = rec->sw_data;
184 else {
185 rec->sw_io += bytes;
186 if (rec->sw_io >= rec->sw_buffer_size)
187 rec->sw_io -=
188 rec->sw_buffer_size;
189 }
190 }
191 }
192 rec->min_period_count += bytes;
193 if (rec->min_period_count >= (rec->hw_buffer_size / 2)) {
194 rec->min_periods += (rec->min_period_count /
195 (rec->hw_buffer_size / 2));
196 #ifdef SND_PCM_INDIRECT2_STAT
197 if ((rec->min_period_count /
198 (rec->hw_buffer_size / 2)) > 7)
199 snd_printk(KERN_DEBUG
200 "STAT: more than 7 (%d) min_adds "
201 "at once - too big to save!\n",
202 (rec->min_period_count /
203 (rec->hw_buffer_size / 2)));
204 else
205 rec->min_adds[(rec->min_period_count /
206 (rec->hw_buffer_size / 2))]++;
207 #endif
208 rec->min_period_count = (rec->min_period_count %
209 (rec->hw_buffer_size / 2));
210 }
211 } else if (isplay && iscopy)
212 rec->min_periods = 0;
213 }
214
215
216
217
218 snd_pcm_uframes_t
219 snd_pcm_indirect2_pointer(struct snd_pcm_substream *substream,
220 struct snd_pcm_indirect2 *rec)
221 {
222 #ifdef SND_PCM_INDIRECT2_STAT
223 rec->pointer_calls++;
224 #endif
225 return bytes_to_frames(substream->runtime, rec->sw_io);
226 }
227
228
229
230
231 static void
232 snd_pcm_indirect2_playback_transfer(struct snd_pcm_substream *substream,
233 struct snd_pcm_indirect2 *rec,
234 snd_pcm_indirect2_copy_t copy,
235 snd_pcm_indirect2_zero_t zero)
236 {
237 struct snd_pcm_runtime *runtime = substream->runtime;
238 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
239
240
241
242
243
244
245 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
246
247 if (diff) {
248 #ifdef SND_PCM_INDIRECT2_STAT
249 rec->lastdifftime = jiffies;
250 #endif
251 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
252 diff += runtime->boundary;
253
254
255
256
257 rec->sw_ready += (int)frames_to_bytes(runtime, diff);
258 rec->appl_ptr = appl_ptr;
259 }
260 if (rec->hw_ready && (rec->sw_ready <= 0)) {
261 unsigned int bytes;
262
263 #ifdef SND_PCM_INDIRECT2_STAT
264 if (rec->firstzerotime == 0) {
265 rec->firstzerotime = jiffies;
266 snd_printk(KERN_DEBUG
267 "STAT: @firstzerotime: mul_elapsed: %d, "
268 "min_period_count: %d\n",
269 rec->mul_elapsed, rec->min_period_count);
270 snd_printk(KERN_DEBUG
271 "STAT: @firstzerotime: sw_io: %d, "
272 "sw_data: %d, appl_ptr: %u\n",
273 rec->sw_io, rec->sw_data,
274 (unsigned int)appl_ptr);
275 }
276 if ((jiffies - rec->firstzerotime) < 3750) {
277 rec->zero_times[(jiffies - rec->firstzerotime)]++;
278 rec->zero_times_saved++;
279 } else
280 rec->zero_times_notsaved++;
281 #endif
282 bytes = zero(substream, rec);
283
284 #ifdef SND_PCM_INDIRECT2_STAT
285 rec->zeros2hw += bytes;
286 if (bytes < 64)
287 rec->zero_sizes[bytes]++;
288 else
289 snd_printk(KERN_DEBUG
290 "STAT: %d zero Bytes copied to hardware at "
291 "once - too big to save!\n",
292 bytes);
293 #endif
294 snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 0,
295 bytes);
296 return;
297 }
298 while (rec->hw_ready && (rec->sw_ready > 0)) {
299
300
301
302 unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
303
304
305 unsigned int bytes = rec->sw_ready;
306
307 if (sw_to_end < bytes)
308 bytes = sw_to_end;
309 if (!bytes)
310 break;
311
312 #ifdef SND_PCM_INDIRECT2_STAT
313 if (rec->firstbytetime == 0)
314 rec->firstbytetime = jiffies;
315 rec->lastbytetime = jiffies;
316 #endif
317
318
319
320
321
322 bytes = copy(substream, rec, bytes);
323 rec->bytes2hw += bytes;
324
325 #ifdef SND_PCM_INDIRECT2_STAT
326 if (bytes < 64)
327 rec->byte_sizes[bytes]++;
328 else
329 snd_printk(KERN_DEBUG
330 "STAT: %d Bytes copied to hardware at once "
331 "- too big to save!\n",
332 bytes);
333 #endif
334
335
336
337 rec->sw_data += bytes;
338 if (rec->sw_data == rec->sw_buffer_size)
339 rec->sw_data = 0;
340
341
342
343
344
345 snd_pcm_indirect2_increase_min_periods(substream, rec, 1, 1,
346 bytes);
347
348
349
350
351
352 rec->sw_ready -= bytes;
353 }
354 return;
355 }
356
357
358
359
360 void
361 snd_pcm_indirect2_playback_interrupt(struct snd_pcm_substream *substream,
362 struct snd_pcm_indirect2 *rec,
363 snd_pcm_indirect2_copy_t copy,
364 snd_pcm_indirect2_zero_t zero)
365 {
366 #ifdef SND_PCM_INDIRECT2_STAT
367 rec->irq_occured++;
368 #endif
369
370 rec->hw_ready = 1;
371
372
373
374
375 snd_pcm_indirect2_playback_transfer(substream, rec, copy, zero);
376
377 if (rec->min_periods >= rec->min_multiple) {
378 #ifdef SND_PCM_INDIRECT2_STAT
379 if ((rec->min_periods / rec->min_multiple) > 7)
380 snd_printk(KERN_DEBUG
381 "STAT: more than 7 (%d) mul_adds - too big "
382 "to save!\n",
383 (rec->min_periods / rec->min_multiple));
384 else
385 rec->mul_adds[(rec->min_periods /
386 rec->min_multiple)]++;
387 rec->mul_elapsed_real += (rec->min_periods /
388 rec->min_multiple);
389 rec->mul_elapsed++;
390 #endif
391 rec->min_periods = (rec->min_periods % rec->min_multiple);
392 snd_pcm_period_elapsed(substream);
393 }
394 }
395
396
397
398
399 static void
400 snd_pcm_indirect2_capture_transfer(struct snd_pcm_substream *substream,
401 struct snd_pcm_indirect2 *rec,
402 snd_pcm_indirect2_copy_t copy,
403 snd_pcm_indirect2_zero_t null)
404 {
405 struct snd_pcm_runtime *runtime = substream->runtime;
406 snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
407 snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
408
409 if (diff) {
410 #ifdef SND_PCM_INDIRECT2_STAT
411 rec->lastdifftime = jiffies;
412 #endif
413 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
414 diff += runtime->boundary;
415 rec->sw_ready -= frames_to_bytes(runtime, diff);
416 rec->appl_ptr = appl_ptr;
417 }
418
419
420
421 if (rec->hw_ready && (rec->sw_ready >= (int)rec->sw_buffer_size)) {
422 unsigned int bytes;
423
424 #ifdef SND_PCM_INDIRECT2_STAT
425 if (rec->firstzerotime == 0) {
426 rec->firstzerotime = jiffies;
427 snd_printk(KERN_DEBUG "STAT: (capture) "
428 "@firstzerotime: mul_elapsed: %d, "
429 "min_period_count: %d\n",
430 rec->mul_elapsed, rec->min_period_count);
431 snd_printk(KERN_DEBUG "STAT: (capture) "
432 "@firstzerotime: sw_io: %d, sw_data: %d, "
433 "appl_ptr: %u\n",
434 rec->sw_io, rec->sw_data,
435 (unsigned int)appl_ptr);
436 }
437 if ((jiffies - rec->firstzerotime) < 3750) {
438 rec->zero_times[(jiffies - rec->firstzerotime)]++;
439 rec->zero_times_saved++;
440 } else
441 rec->zero_times_notsaved++;
442 #endif
443 bytes = null(substream, rec);
444
445 #ifdef SND_PCM_INDIRECT2_STAT
446 rec->zeros2hw += bytes;
447 if (bytes < 64)
448 rec->zero_sizes[bytes]++;
449 else
450 snd_printk(KERN_DEBUG
451 "STAT: (capture) %d zero Bytes copied to "
452 "hardware at once - too big to save!\n",
453 bytes);
454 #endif
455 snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 0,
456 bytes);
457
458 rec->sw_io = SNDRV_PCM_POS_XRUN;
459 return;
460 }
461 while (rec->hw_ready && (rec->sw_ready < (int)rec->sw_buffer_size)) {
462
463
464
465 size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
466
467
468
469
470 size_t bytes = rec->sw_buffer_size - rec->sw_ready;
471
472
473
474
475 if (sw_to_end < bytes)
476 bytes = sw_to_end;
477 if (!bytes)
478 break;
479
480 #ifdef SND_PCM_INDIRECT2_STAT
481 if (rec->firstbytetime == 0)
482 rec->firstbytetime = jiffies;
483 rec->lastbytetime = jiffies;
484 #endif
485
486
487
488
489
490 bytes = copy(substream, rec, bytes);
491 rec->bytes2hw += bytes;
492
493 #ifdef SND_PCM_INDIRECT2_STAT
494 if (bytes < 64)
495 rec->byte_sizes[bytes]++;
496 else
497 snd_printk(KERN_DEBUG
498 "STAT: (capture) %d Bytes copied to "
499 "hardware at once - too big to save!\n",
500 bytes);
501 #endif
502
503
504
505 rec->sw_data += bytes;
506 if (rec->sw_data == rec->sw_buffer_size)
507 rec->sw_data = 0;
508
509 snd_pcm_indirect2_increase_min_periods(substream, rec, 0, 1,
510 bytes);
511
512
513
514
515 rec->sw_ready += bytes;
516 }
517 return;
518 }
519
520
521
522
523 void
524 snd_pcm_indirect2_capture_interrupt(struct snd_pcm_substream *substream,
525 struct snd_pcm_indirect2 *rec,
526 snd_pcm_indirect2_copy_t copy,
527 snd_pcm_indirect2_zero_t null)
528 {
529 #ifdef SND_PCM_INDIRECT2_STAT
530 rec->irq_occured++;
531 #endif
532
533
534
535 rec->hw_ready = 1;
536
537
538
539
540 snd_pcm_indirect2_capture_transfer(substream, rec, copy, null);
541
542 if (rec->min_periods >= rec->min_multiple) {
543
544 #ifdef SND_PCM_INDIRECT2_STAT
545 if ((rec->min_periods / rec->min_multiple) > 7)
546 snd_printk(KERN_DEBUG
547 "STAT: more than 7 (%d) mul_adds - "
548 "too big to save!\n",
549 (rec->min_periods / rec->min_multiple));
550 else
551 rec->mul_adds[(rec->min_periods /
552 rec->min_multiple)]++;
553 rec->mul_elapsed_real += (rec->min_periods /
554 rec->min_multiple);
555 rec->mul_elapsed++;
556 #endif
557 rec->min_periods = (rec->min_periods % rec->min_multiple);
558 snd_pcm_period_elapsed(substream);
559 }
560 }