diff options
Diffstat (limited to 'sound/core/pcm_lib.c')
-rw-r--r-- | sound/core/pcm_lib.c | 668 |
1 files changed, 253 insertions, 415 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 877176067072..a93a4235a332 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
34 | #include <sound/timer.h> | 34 | #include <sound/timer.h> |
35 | 35 | ||
36 | #include "pcm_local.h" | ||
37 | |||
36 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | 38 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG |
37 | #define CREATE_TRACE_POINTS | 39 | #define CREATE_TRACE_POINTS |
38 | #include "pcm_trace.h" | 40 | #include "pcm_trace.h" |
@@ -40,8 +42,12 @@ | |||
40 | #define trace_hwptr(substream, pos, in_interrupt) | 42 | #define trace_hwptr(substream, pos, in_interrupt) |
41 | #define trace_xrun(substream) | 43 | #define trace_xrun(substream) |
42 | #define trace_hw_ptr_error(substream, reason) | 44 | #define trace_hw_ptr_error(substream, reason) |
45 | #define trace_applptr(substream, prev, curr) | ||
43 | #endif | 46 | #endif |
44 | 47 | ||
48 | static int fill_silence_frames(struct snd_pcm_substream *substream, | ||
49 | snd_pcm_uframes_t off, snd_pcm_uframes_t frames); | ||
50 | |||
45 | /* | 51 | /* |
46 | * fill ring buffer with silence | 52 | * fill ring buffer with silence |
47 | * runtime->silence_start: starting pointer to silence area | 53 | * runtime->silence_start: starting pointer to silence area |
@@ -55,18 +61,20 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
55 | { | 61 | { |
56 | struct snd_pcm_runtime *runtime = substream->runtime; | 62 | struct snd_pcm_runtime *runtime = substream->runtime; |
57 | snd_pcm_uframes_t frames, ofs, transfer; | 63 | snd_pcm_uframes_t frames, ofs, transfer; |
64 | int err; | ||
58 | 65 | ||
59 | if (runtime->silence_size < runtime->boundary) { | 66 | if (runtime->silence_size < runtime->boundary) { |
60 | snd_pcm_sframes_t noise_dist, n; | 67 | snd_pcm_sframes_t noise_dist, n; |
61 | if (runtime->silence_start != runtime->control->appl_ptr) { | 68 | snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr); |
62 | n = runtime->control->appl_ptr - runtime->silence_start; | 69 | if (runtime->silence_start != appl_ptr) { |
70 | n = appl_ptr - runtime->silence_start; | ||
63 | if (n < 0) | 71 | if (n < 0) |
64 | n += runtime->boundary; | 72 | n += runtime->boundary; |
65 | if ((snd_pcm_uframes_t)n < runtime->silence_filled) | 73 | if ((snd_pcm_uframes_t)n < runtime->silence_filled) |
66 | runtime->silence_filled -= n; | 74 | runtime->silence_filled -= n; |
67 | else | 75 | else |
68 | runtime->silence_filled = 0; | 76 | runtime->silence_filled = 0; |
69 | runtime->silence_start = runtime->control->appl_ptr; | 77 | runtime->silence_start = appl_ptr; |
70 | } | 78 | } |
71 | if (runtime->silence_filled >= runtime->buffer_size) | 79 | if (runtime->silence_filled >= runtime->buffer_size) |
72 | return; | 80 | return; |
@@ -107,33 +115,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
107 | ofs = runtime->silence_start % runtime->buffer_size; | 115 | ofs = runtime->silence_start % runtime->buffer_size; |
108 | while (frames > 0) { | 116 | while (frames > 0) { |
109 | transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; | 117 | transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; |
110 | if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || | 118 | err = fill_silence_frames(substream, ofs, transfer); |
111 | runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) { | 119 | snd_BUG_ON(err < 0); |
112 | if (substream->ops->silence) { | ||
113 | int err; | ||
114 | err = substream->ops->silence(substream, -1, ofs, transfer); | ||
115 | snd_BUG_ON(err < 0); | ||
116 | } else { | ||
117 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs); | ||
118 | snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels); | ||
119 | } | ||
120 | } else { | ||
121 | unsigned int c; | ||
122 | unsigned int channels = runtime->channels; | ||
123 | if (substream->ops->silence) { | ||
124 | for (c = 0; c < channels; ++c) { | ||
125 | int err; | ||
126 | err = substream->ops->silence(substream, c, ofs, transfer); | ||
127 | snd_BUG_ON(err < 0); | ||
128 | } | ||
129 | } else { | ||
130 | size_t dma_csize = runtime->dma_bytes / channels; | ||
131 | for (c = 0; c < channels; ++c) { | ||
132 | char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs); | ||
133 | snd_pcm_format_set_silence(runtime->format, hwbuf, transfer); | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | runtime->silence_filled += transfer; | 120 | runtime->silence_filled += transfer; |
138 | frames -= transfer; | 121 | frames -= transfer; |
139 | ofs = 0; | 122 | ofs = 0; |
@@ -508,7 +491,6 @@ void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, | |||
508 | for (substream = stream->substream; substream != NULL; substream = substream->next) | 491 | for (substream = stream->substream; substream != NULL; substream = substream->next) |
509 | substream->ops = ops; | 492 | substream->ops = ops; |
510 | } | 493 | } |
511 | |||
512 | EXPORT_SYMBOL(snd_pcm_set_ops); | 494 | EXPORT_SYMBOL(snd_pcm_set_ops); |
513 | 495 | ||
514 | /** | 496 | /** |
@@ -526,7 +508,6 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream) | |||
526 | runtime->sync.id32[2] = -1; | 508 | runtime->sync.id32[2] = -1; |
527 | runtime->sync.id32[3] = -1; | 509 | runtime->sync.id32[3] = -1; |
528 | } | 510 | } |
529 | |||
530 | EXPORT_SYMBOL(snd_pcm_set_sync); | 511 | EXPORT_SYMBOL(snd_pcm_set_sync); |
531 | 512 | ||
532 | /* | 513 | /* |
@@ -643,7 +624,6 @@ int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v) | |||
643 | } | 624 | } |
644 | return changed; | 625 | return changed; |
645 | } | 626 | } |
646 | |||
647 | EXPORT_SYMBOL(snd_interval_refine); | 627 | EXPORT_SYMBOL(snd_interval_refine); |
648 | 628 | ||
649 | static int snd_interval_refine_first(struct snd_interval *i) | 629 | static int snd_interval_refine_first(struct snd_interval *i) |
@@ -906,7 +886,6 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
906 | } | 886 | } |
907 | return err; | 887 | return err; |
908 | } | 888 | } |
909 | |||
910 | EXPORT_SYMBOL(snd_interval_ratnum); | 889 | EXPORT_SYMBOL(snd_interval_ratnum); |
911 | 890 | ||
912 | /** | 891 | /** |
@@ -1044,7 +1023,6 @@ int snd_interval_list(struct snd_interval *i, unsigned int count, | |||
1044 | } | 1023 | } |
1045 | return snd_interval_refine(i, &list_range); | 1024 | return snd_interval_refine(i, &list_range); |
1046 | } | 1025 | } |
1047 | |||
1048 | EXPORT_SYMBOL(snd_interval_list); | 1026 | EXPORT_SYMBOL(snd_interval_list); |
1049 | 1027 | ||
1050 | /** | 1028 | /** |
@@ -1183,7 +1161,6 @@ int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond, | |||
1183 | va_end(args); | 1161 | va_end(args); |
1184 | return 0; | 1162 | return 0; |
1185 | } | 1163 | } |
1186 | |||
1187 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); | 1164 | EXPORT_SYMBOL(snd_pcm_hw_rule_add); |
1188 | 1165 | ||
1189 | /** | 1166 | /** |
@@ -1247,7 +1224,6 @@ int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_pa | |||
1247 | struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; | 1224 | struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; |
1248 | return snd_interval_setinteger(constrs_interval(constrs, var)); | 1225 | return snd_interval_setinteger(constrs_interval(constrs, var)); |
1249 | } | 1226 | } |
1250 | |||
1251 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); | 1227 | EXPORT_SYMBOL(snd_pcm_hw_constraint_integer); |
1252 | 1228 | ||
1253 | /** | 1229 | /** |
@@ -1273,7 +1249,6 @@ int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_par | |||
1273 | t.integer = 0; | 1249 | t.integer = 0; |
1274 | return snd_interval_refine(constrs_interval(constrs, var), &t); | 1250 | return snd_interval_refine(constrs_interval(constrs, var), &t); |
1275 | } | 1251 | } |
1276 | |||
1277 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); | 1252 | EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax); |
1278 | 1253 | ||
1279 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, | 1254 | static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params, |
@@ -1304,7 +1279,6 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime, | |||
1304 | snd_pcm_hw_rule_list, (void *)l, | 1279 | snd_pcm_hw_rule_list, (void *)l, |
1305 | var, -1); | 1280 | var, -1); |
1306 | } | 1281 | } |
1307 | |||
1308 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); | 1282 | EXPORT_SYMBOL(snd_pcm_hw_constraint_list); |
1309 | 1283 | ||
1310 | static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, | 1284 | static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params, |
@@ -1371,7 +1345,6 @@ int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, | |||
1371 | snd_pcm_hw_rule_ratnums, (void *)r, | 1345 | snd_pcm_hw_rule_ratnums, (void *)r, |
1372 | var, -1); | 1346 | var, -1); |
1373 | } | 1347 | } |
1374 | |||
1375 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); | 1348 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums); |
1376 | 1349 | ||
1377 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, | 1350 | static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params, |
@@ -1406,7 +1379,6 @@ int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime, | |||
1406 | snd_pcm_hw_rule_ratdens, (void *)r, | 1379 | snd_pcm_hw_rule_ratdens, (void *)r, |
1407 | var, -1); | 1380 | var, -1); |
1408 | } | 1381 | } |
1409 | |||
1410 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); | 1382 | EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens); |
1411 | 1383 | ||
1412 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, | 1384 | static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, |
@@ -1415,7 +1387,8 @@ static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params, | |||
1415 | unsigned int l = (unsigned long) rule->private; | 1387 | unsigned int l = (unsigned long) rule->private; |
1416 | int width = l & 0xffff; | 1388 | int width = l & 0xffff; |
1417 | unsigned int msbits = l >> 16; | 1389 | unsigned int msbits = l >> 16; |
1418 | struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | 1390 | const struct snd_interval *i = |
1391 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | ||
1419 | 1392 | ||
1420 | if (!snd_interval_single(i)) | 1393 | if (!snd_interval_single(i)) |
1421 | return 0; | 1394 | return 0; |
@@ -1452,7 +1425,6 @@ int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime, | |||
1452 | (void*) l, | 1425 | (void*) l, |
1453 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | 1426 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); |
1454 | } | 1427 | } |
1455 | |||
1456 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); | 1428 | EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits); |
1457 | 1429 | ||
1458 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, | 1430 | static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params, |
@@ -1480,7 +1452,6 @@ int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime, | |||
1480 | snd_pcm_hw_rule_step, (void *) step, | 1452 | snd_pcm_hw_rule_step, (void *) step, |
1481 | var, -1); | 1453 | var, -1); |
1482 | } | 1454 | } |
1483 | |||
1484 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); | 1455 | EXPORT_SYMBOL(snd_pcm_hw_constraint_step); |
1485 | 1456 | ||
1486 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) | 1457 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) |
@@ -1511,7 +1482,6 @@ int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime, | |||
1511 | snd_pcm_hw_rule_pow2, NULL, | 1482 | snd_pcm_hw_rule_pow2, NULL, |
1512 | var, -1); | 1483 | var, -1); |
1513 | } | 1484 | } |
1514 | |||
1515 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); | 1485 | EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2); |
1516 | 1486 | ||
1517 | static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, | 1487 | static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params, |
@@ -1570,7 +1540,6 @@ void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params) | |||
1570 | _snd_pcm_hw_param_any(params, k); | 1540 | _snd_pcm_hw_param_any(params, k); |
1571 | params->info = ~0U; | 1541 | params->info = ~0U; |
1572 | } | 1542 | } |
1573 | |||
1574 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); | 1543 | EXPORT_SYMBOL(_snd_pcm_hw_params_any); |
1575 | 1544 | ||
1576 | /** | 1545 | /** |
@@ -1603,7 +1572,6 @@ int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params, | |||
1603 | } | 1572 | } |
1604 | return -EINVAL; | 1573 | return -EINVAL; |
1605 | } | 1574 | } |
1606 | |||
1607 | EXPORT_SYMBOL(snd_pcm_hw_param_value); | 1575 | EXPORT_SYMBOL(snd_pcm_hw_param_value); |
1608 | 1576 | ||
1609 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | 1577 | void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, |
@@ -1621,7 +1589,6 @@ void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params, | |||
1621 | snd_BUG(); | 1589 | snd_BUG(); |
1622 | } | 1590 | } |
1623 | } | 1591 | } |
1624 | |||
1625 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); | 1592 | EXPORT_SYMBOL(_snd_pcm_hw_param_setempty); |
1626 | 1593 | ||
1627 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, | 1594 | static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params, |
@@ -1668,7 +1635,6 @@ int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm, | |||
1668 | } | 1635 | } |
1669 | return snd_pcm_hw_param_value(params, var, dir); | 1636 | return snd_pcm_hw_param_value(params, var, dir); |
1670 | } | 1637 | } |
1671 | |||
1672 | EXPORT_SYMBOL(snd_pcm_hw_param_first); | 1638 | EXPORT_SYMBOL(snd_pcm_hw_param_first); |
1673 | 1639 | ||
1674 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, | 1640 | static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params, |
@@ -1715,48 +1681,8 @@ int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm, | |||
1715 | } | 1681 | } |
1716 | return snd_pcm_hw_param_value(params, var, dir); | 1682 | return snd_pcm_hw_param_value(params, var, dir); |
1717 | } | 1683 | } |
1718 | |||
1719 | EXPORT_SYMBOL(snd_pcm_hw_param_last); | 1684 | EXPORT_SYMBOL(snd_pcm_hw_param_last); |
1720 | 1685 | ||
1721 | /** | ||
1722 | * snd_pcm_hw_param_choose - choose a configuration defined by @params | ||
1723 | * @pcm: PCM instance | ||
1724 | * @params: the hw_params instance | ||
1725 | * | ||
1726 | * Choose one configuration from configuration space defined by @params. | ||
1727 | * The configuration chosen is that obtained fixing in this order: | ||
1728 | * first access, first format, first subformat, min channels, | ||
1729 | * min rate, min period time, max buffer size, min tick time | ||
1730 | * | ||
1731 | * Return: Zero if successful, or a negative error code on failure. | ||
1732 | */ | ||
1733 | int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, | ||
1734 | struct snd_pcm_hw_params *params) | ||
1735 | { | ||
1736 | static int vars[] = { | ||
1737 | SNDRV_PCM_HW_PARAM_ACCESS, | ||
1738 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1739 | SNDRV_PCM_HW_PARAM_SUBFORMAT, | ||
1740 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1741 | SNDRV_PCM_HW_PARAM_RATE, | ||
1742 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
1743 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1744 | SNDRV_PCM_HW_PARAM_TICK_TIME, | ||
1745 | -1 | ||
1746 | }; | ||
1747 | int err, *v; | ||
1748 | |||
1749 | for (v = vars; *v != -1; v++) { | ||
1750 | if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE) | ||
1751 | err = snd_pcm_hw_param_first(pcm, params, *v, NULL); | ||
1752 | else | ||
1753 | err = snd_pcm_hw_param_last(pcm, params, *v, NULL); | ||
1754 | if (snd_BUG_ON(err < 0)) | ||
1755 | return err; | ||
1756 | } | ||
1757 | return 0; | ||
1758 | } | ||
1759 | |||
1760 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, | 1686 | static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream, |
1761 | void *arg) | 1687 | void *arg) |
1762 | { | 1688 | { |
@@ -1843,8 +1769,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
1843 | unsigned int cmd, void *arg) | 1769 | unsigned int cmd, void *arg) |
1844 | { | 1770 | { |
1845 | switch (cmd) { | 1771 | switch (cmd) { |
1846 | case SNDRV_PCM_IOCTL1_INFO: | ||
1847 | return 0; | ||
1848 | case SNDRV_PCM_IOCTL1_RESET: | 1772 | case SNDRV_PCM_IOCTL1_RESET: |
1849 | return snd_pcm_lib_ioctl_reset(substream, arg); | 1773 | return snd_pcm_lib_ioctl_reset(substream, arg); |
1850 | case SNDRV_PCM_IOCTL1_CHANNEL_INFO: | 1774 | case SNDRV_PCM_IOCTL1_CHANNEL_INFO: |
@@ -1854,7 +1778,6 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | |||
1854 | } | 1778 | } |
1855 | return -ENXIO; | 1779 | return -ENXIO; |
1856 | } | 1780 | } |
1857 | |||
1858 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); | 1781 | EXPORT_SYMBOL(snd_pcm_lib_ioctl); |
1859 | 1782 | ||
1860 | /** | 1783 | /** |
@@ -1890,7 +1813,6 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
1890 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); | 1813 | kill_fasync(&runtime->fasync, SIGIO, POLL_IN); |
1891 | snd_pcm_stream_unlock_irqrestore(substream, flags); | 1814 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
1892 | } | 1815 | } |
1893 | |||
1894 | EXPORT_SYMBOL(snd_pcm_period_elapsed); | 1816 | EXPORT_SYMBOL(snd_pcm_period_elapsed); |
1895 | 1817 | ||
1896 | /* | 1818 | /* |
@@ -1985,129 +1907,147 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1985 | return err; | 1907 | return err; |
1986 | } | 1908 | } |
1987 | 1909 | ||
1988 | static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream, | 1910 | typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream, |
1989 | unsigned int hwoff, | 1911 | int channel, unsigned long hwoff, |
1990 | unsigned long data, unsigned int off, | 1912 | void *buf, unsigned long bytes); |
1991 | snd_pcm_uframes_t frames) | 1913 | |
1914 | typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *, | ||
1915 | snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f); | ||
1916 | |||
1917 | /* calculate the target DMA-buffer position to be written/read */ | ||
1918 | static void *get_dma_ptr(struct snd_pcm_runtime *runtime, | ||
1919 | int channel, unsigned long hwoff) | ||
1992 | { | 1920 | { |
1993 | struct snd_pcm_runtime *runtime = substream->runtime; | 1921 | return runtime->dma_area + hwoff + |
1994 | int err; | 1922 | channel * (runtime->dma_bytes / runtime->channels); |
1995 | char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); | 1923 | } |
1996 | if (substream->ops->copy) { | 1924 | |
1997 | if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) | 1925 | /* default copy_user ops for write; used for both interleaved and non- modes */ |
1998 | return err; | 1926 | static int default_write_copy(struct snd_pcm_substream *substream, |
1999 | } else { | 1927 | int channel, unsigned long hwoff, |
2000 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); | 1928 | void *buf, unsigned long bytes) |
2001 | if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames))) | 1929 | { |
2002 | return -EFAULT; | 1930 | if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff), |
2003 | } | 1931 | (void __user *)buf, bytes)) |
1932 | return -EFAULT; | ||
2004 | return 0; | 1933 | return 0; |
2005 | } | 1934 | } |
2006 | |||
2007 | typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff, | ||
2008 | unsigned long data, unsigned int off, | ||
2009 | snd_pcm_uframes_t size); | ||
2010 | 1935 | ||
2011 | static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | 1936 | /* default copy_kernel ops for write */ |
2012 | unsigned long data, | 1937 | static int default_write_copy_kernel(struct snd_pcm_substream *substream, |
2013 | snd_pcm_uframes_t size, | 1938 | int channel, unsigned long hwoff, |
2014 | int nonblock, | 1939 | void *buf, unsigned long bytes) |
2015 | transfer_f transfer) | 1940 | { |
1941 | memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes); | ||
1942 | return 0; | ||
1943 | } | ||
1944 | |||
1945 | /* fill silence instead of copy data; called as a transfer helper | ||
1946 | * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when | ||
1947 | * a NULL buffer is passed | ||
1948 | */ | ||
1949 | static int fill_silence(struct snd_pcm_substream *substream, int channel, | ||
1950 | unsigned long hwoff, void *buf, unsigned long bytes) | ||
2016 | { | 1951 | { |
2017 | struct snd_pcm_runtime *runtime = substream->runtime; | 1952 | struct snd_pcm_runtime *runtime = substream->runtime; |
2018 | snd_pcm_uframes_t xfer = 0; | ||
2019 | snd_pcm_uframes_t offset = 0; | ||
2020 | snd_pcm_uframes_t avail; | ||
2021 | int err = 0; | ||
2022 | 1953 | ||
2023 | if (size == 0) | 1954 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) |
2024 | return 0; | 1955 | return 0; |
1956 | if (substream->ops->fill_silence) | ||
1957 | return substream->ops->fill_silence(substream, channel, | ||
1958 | hwoff, bytes); | ||
2025 | 1959 | ||
2026 | snd_pcm_stream_lock_irq(substream); | 1960 | snd_pcm_format_set_silence(runtime->format, |
2027 | switch (runtime->status->state) { | 1961 | get_dma_ptr(runtime, channel, hwoff), |
2028 | case SNDRV_PCM_STATE_PREPARED: | 1962 | bytes_to_samples(runtime, bytes)); |
2029 | case SNDRV_PCM_STATE_RUNNING: | 1963 | return 0; |
2030 | case SNDRV_PCM_STATE_PAUSED: | 1964 | } |
2031 | break; | ||
2032 | case SNDRV_PCM_STATE_XRUN: | ||
2033 | err = -EPIPE; | ||
2034 | goto _end_unlock; | ||
2035 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2036 | err = -ESTRPIPE; | ||
2037 | goto _end_unlock; | ||
2038 | default: | ||
2039 | err = -EBADFD; | ||
2040 | goto _end_unlock; | ||
2041 | } | ||
2042 | 1965 | ||
2043 | runtime->twake = runtime->control->avail_min ? : 1; | 1966 | /* default copy_user ops for read; used for both interleaved and non- modes */ |
2044 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 1967 | static int default_read_copy(struct snd_pcm_substream *substream, |
2045 | snd_pcm_update_hw_ptr(substream); | 1968 | int channel, unsigned long hwoff, |
2046 | avail = snd_pcm_playback_avail(runtime); | 1969 | void *buf, unsigned long bytes) |
2047 | while (size > 0) { | 1970 | { |
2048 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1971 | if (copy_to_user((void __user *)buf, |
2049 | snd_pcm_uframes_t cont; | 1972 | get_dma_ptr(substream->runtime, channel, hwoff), |
2050 | if (!avail) { | 1973 | bytes)) |
2051 | if (nonblock) { | 1974 | return -EFAULT; |
2052 | err = -EAGAIN; | 1975 | return 0; |
2053 | goto _end_unlock; | 1976 | } |
2054 | } | ||
2055 | runtime->twake = min_t(snd_pcm_uframes_t, size, | ||
2056 | runtime->control->avail_min ? : 1); | ||
2057 | err = wait_for_avail(substream, &avail); | ||
2058 | if (err < 0) | ||
2059 | goto _end_unlock; | ||
2060 | } | ||
2061 | frames = size > avail ? avail : size; | ||
2062 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | ||
2063 | if (frames > cont) | ||
2064 | frames = cont; | ||
2065 | if (snd_BUG_ON(!frames)) { | ||
2066 | runtime->twake = 0; | ||
2067 | snd_pcm_stream_unlock_irq(substream); | ||
2068 | return -EINVAL; | ||
2069 | } | ||
2070 | appl_ptr = runtime->control->appl_ptr; | ||
2071 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2072 | snd_pcm_stream_unlock_irq(substream); | ||
2073 | err = transfer(substream, appl_ofs, data, offset, frames); | ||
2074 | snd_pcm_stream_lock_irq(substream); | ||
2075 | if (err < 0) | ||
2076 | goto _end_unlock; | ||
2077 | switch (runtime->status->state) { | ||
2078 | case SNDRV_PCM_STATE_XRUN: | ||
2079 | err = -EPIPE; | ||
2080 | goto _end_unlock; | ||
2081 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2082 | err = -ESTRPIPE; | ||
2083 | goto _end_unlock; | ||
2084 | default: | ||
2085 | break; | ||
2086 | } | ||
2087 | appl_ptr += frames; | ||
2088 | if (appl_ptr >= runtime->boundary) | ||
2089 | appl_ptr -= runtime->boundary; | ||
2090 | runtime->control->appl_ptr = appl_ptr; | ||
2091 | if (substream->ops->ack) | ||
2092 | substream->ops->ack(substream); | ||
2093 | 1977 | ||
2094 | offset += frames; | 1978 | /* default copy_kernel ops for read */ |
2095 | size -= frames; | 1979 | static int default_read_copy_kernel(struct snd_pcm_substream *substream, |
2096 | xfer += frames; | 1980 | int channel, unsigned long hwoff, |
2097 | avail -= frames; | 1981 | void *buf, unsigned long bytes) |
2098 | if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && | 1982 | { |
2099 | snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { | 1983 | memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes); |
2100 | err = snd_pcm_start(substream); | 1984 | return 0; |
2101 | if (err < 0) | 1985 | } |
2102 | goto _end_unlock; | 1986 | |
2103 | } | 1987 | /* call transfer function with the converted pointers and sizes; |
1988 | * for interleaved mode, it's one shot for all samples | ||
1989 | */ | ||
1990 | static int interleaved_copy(struct snd_pcm_substream *substream, | ||
1991 | snd_pcm_uframes_t hwoff, void *data, | ||
1992 | snd_pcm_uframes_t off, | ||
1993 | snd_pcm_uframes_t frames, | ||
1994 | pcm_transfer_f transfer) | ||
1995 | { | ||
1996 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1997 | |||
1998 | /* convert to bytes */ | ||
1999 | hwoff = frames_to_bytes(runtime, hwoff); | ||
2000 | off = frames_to_bytes(runtime, off); | ||
2001 | frames = frames_to_bytes(runtime, frames); | ||
2002 | return transfer(substream, 0, hwoff, data + off, frames); | ||
2003 | } | ||
2004 | |||
2005 | /* call transfer function with the converted pointers and sizes for each | ||
2006 | * non-interleaved channel; when buffer is NULL, silencing instead of copying | ||
2007 | */ | ||
2008 | static int noninterleaved_copy(struct snd_pcm_substream *substream, | ||
2009 | snd_pcm_uframes_t hwoff, void *data, | ||
2010 | snd_pcm_uframes_t off, | ||
2011 | snd_pcm_uframes_t frames, | ||
2012 | pcm_transfer_f transfer) | ||
2013 | { | ||
2014 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2015 | int channels = runtime->channels; | ||
2016 | void **bufs = data; | ||
2017 | int c, err; | ||
2018 | |||
2019 | /* convert to bytes; note that it's not frames_to_bytes() here. | ||
2020 | * in non-interleaved mode, we copy for each channel, thus | ||
2021 | * each copy is n_samples bytes x channels = whole frames. | ||
2022 | */ | ||
2023 | off = samples_to_bytes(runtime, off); | ||
2024 | frames = samples_to_bytes(runtime, frames); | ||
2025 | hwoff = samples_to_bytes(runtime, hwoff); | ||
2026 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2027 | if (!data || !*bufs) | ||
2028 | err = fill_silence(substream, c, hwoff, NULL, frames); | ||
2029 | else | ||
2030 | err = transfer(substream, c, hwoff, *bufs + off, | ||
2031 | frames); | ||
2032 | if (err < 0) | ||
2033 | return err; | ||
2104 | } | 2034 | } |
2105 | _end_unlock: | 2035 | return 0; |
2106 | runtime->twake = 0; | 2036 | } |
2107 | if (xfer > 0 && err >= 0) | 2037 | |
2108 | snd_pcm_update_state(substream, runtime); | 2038 | /* fill silence on the given buffer position; |
2109 | snd_pcm_stream_unlock_irq(substream); | 2039 | * called from snd_pcm_playback_silence() |
2110 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2040 | */ |
2041 | static int fill_silence_frames(struct snd_pcm_substream *substream, | ||
2042 | snd_pcm_uframes_t off, snd_pcm_uframes_t frames) | ||
2043 | { | ||
2044 | if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || | ||
2045 | substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) | ||
2046 | return interleaved_copy(substream, off, NULL, 0, frames, | ||
2047 | fill_silence); | ||
2048 | else | ||
2049 | return noninterleaved_copy(substream, off, NULL, 0, frames, | ||
2050 | fill_silence); | ||
2111 | } | 2051 | } |
2112 | 2052 | ||
2113 | /* sanity-check for read/write methods */ | 2053 | /* sanity-check for read/write methods */ |
@@ -2117,164 +2057,137 @@ static int pcm_sanity_check(struct snd_pcm_substream *substream) | |||
2117 | if (PCM_RUNTIME_CHECK(substream)) | 2057 | if (PCM_RUNTIME_CHECK(substream)) |
2118 | return -ENXIO; | 2058 | return -ENXIO; |
2119 | runtime = substream->runtime; | 2059 | runtime = substream->runtime; |
2120 | if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area)) | 2060 | if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area)) |
2121 | return -EINVAL; | 2061 | return -EINVAL; |
2122 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | 2062 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
2123 | return -EBADFD; | 2063 | return -EBADFD; |
2124 | return 0; | 2064 | return 0; |
2125 | } | 2065 | } |
2126 | 2066 | ||
2127 | snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size) | 2067 | static int pcm_accessible_state(struct snd_pcm_runtime *runtime) |
2128 | { | 2068 | { |
2129 | struct snd_pcm_runtime *runtime; | 2069 | switch (runtime->status->state) { |
2130 | int nonblock; | 2070 | case SNDRV_PCM_STATE_PREPARED: |
2131 | int err; | 2071 | case SNDRV_PCM_STATE_RUNNING: |
2132 | 2072 | case SNDRV_PCM_STATE_PAUSED: | |
2133 | err = pcm_sanity_check(substream); | 2073 | return 0; |
2134 | if (err < 0) | 2074 | case SNDRV_PCM_STATE_XRUN: |
2135 | return err; | 2075 | return -EPIPE; |
2136 | runtime = substream->runtime; | 2076 | case SNDRV_PCM_STATE_SUSPENDED: |
2137 | nonblock = !!(substream->f_flags & O_NONBLOCK); | 2077 | return -ESTRPIPE; |
2138 | 2078 | default: | |
2139 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && | 2079 | return -EBADFD; |
2140 | runtime->channels > 1) | 2080 | } |
2141 | return -EINVAL; | ||
2142 | return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock, | ||
2143 | snd_pcm_lib_write_transfer); | ||
2144 | } | 2081 | } |
2145 | 2082 | ||
2146 | EXPORT_SYMBOL(snd_pcm_lib_write); | 2083 | /* update to the given appl_ptr and call ack callback if needed; |
2147 | 2084 | * when an error is returned, take back to the original value | |
2148 | static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream, | 2085 | */ |
2149 | unsigned int hwoff, | 2086 | int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream, |
2150 | unsigned long data, unsigned int off, | 2087 | snd_pcm_uframes_t appl_ptr) |
2151 | snd_pcm_uframes_t frames) | ||
2152 | { | 2088 | { |
2153 | struct snd_pcm_runtime *runtime = substream->runtime; | 2089 | struct snd_pcm_runtime *runtime = substream->runtime; |
2154 | int err; | 2090 | snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr; |
2155 | void __user **bufs = (void __user **)data; | 2091 | int ret; |
2156 | int channels = runtime->channels; | 2092 | |
2157 | int c; | 2093 | if (old_appl_ptr == appl_ptr) |
2158 | if (substream->ops->copy) { | 2094 | return 0; |
2159 | if (snd_BUG_ON(!substream->ops->silence)) | 2095 | |
2160 | return -EINVAL; | 2096 | runtime->control->appl_ptr = appl_ptr; |
2161 | for (c = 0; c < channels; ++c, ++bufs) { | 2097 | if (substream->ops->ack) { |
2162 | if (*bufs == NULL) { | 2098 | ret = substream->ops->ack(substream); |
2163 | if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0) | 2099 | if (ret < 0) { |
2164 | return err; | 2100 | runtime->control->appl_ptr = old_appl_ptr; |
2165 | } else { | 2101 | return ret; |
2166 | char __user *buf = *bufs + samples_to_bytes(runtime, off); | ||
2167 | if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) | ||
2168 | return err; | ||
2169 | } | ||
2170 | } | ||
2171 | } else { | ||
2172 | /* default transfer behaviour */ | ||
2173 | size_t dma_csize = runtime->dma_bytes / channels; | ||
2174 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2175 | char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); | ||
2176 | if (*bufs == NULL) { | ||
2177 | snd_pcm_format_set_silence(runtime->format, hwbuf, frames); | ||
2178 | } else { | ||
2179 | char __user *buf = *bufs + samples_to_bytes(runtime, off); | ||
2180 | if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames))) | ||
2181 | return -EFAULT; | ||
2182 | } | ||
2183 | } | 2102 | } |
2184 | } | 2103 | } |
2104 | |||
2105 | trace_applptr(substream, old_appl_ptr, appl_ptr); | ||
2106 | |||
2185 | return 0; | 2107 | return 0; |
2186 | } | 2108 | } |
2187 | 2109 | ||
2188 | snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream, | 2110 | /* the common loop for read/write data */ |
2189 | void __user **bufs, | 2111 | snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, |
2190 | snd_pcm_uframes_t frames) | 2112 | void *data, bool interleaved, |
2113 | snd_pcm_uframes_t size, bool in_kernel) | ||
2191 | { | 2114 | { |
2192 | struct snd_pcm_runtime *runtime; | 2115 | struct snd_pcm_runtime *runtime = substream->runtime; |
2193 | int nonblock; | 2116 | snd_pcm_uframes_t xfer = 0; |
2117 | snd_pcm_uframes_t offset = 0; | ||
2118 | snd_pcm_uframes_t avail; | ||
2119 | pcm_copy_f writer; | ||
2120 | pcm_transfer_f transfer; | ||
2121 | bool nonblock; | ||
2122 | bool is_playback; | ||
2194 | int err; | 2123 | int err; |
2195 | 2124 | ||
2196 | err = pcm_sanity_check(substream); | 2125 | err = pcm_sanity_check(substream); |
2197 | if (err < 0) | 2126 | if (err < 0) |
2198 | return err; | 2127 | return err; |
2199 | runtime = substream->runtime; | ||
2200 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2201 | |||
2202 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | ||
2203 | return -EINVAL; | ||
2204 | return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames, | ||
2205 | nonblock, snd_pcm_lib_writev_transfer); | ||
2206 | } | ||
2207 | |||
2208 | EXPORT_SYMBOL(snd_pcm_lib_writev); | ||
2209 | 2128 | ||
2210 | static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, | 2129 | is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
2211 | unsigned int hwoff, | 2130 | if (interleaved) { |
2212 | unsigned long data, unsigned int off, | 2131 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && |
2213 | snd_pcm_uframes_t frames) | 2132 | runtime->channels > 1) |
2214 | { | 2133 | return -EINVAL; |
2215 | struct snd_pcm_runtime *runtime = substream->runtime; | 2134 | writer = interleaved_copy; |
2216 | int err; | ||
2217 | char __user *buf = (char __user *) data + frames_to_bytes(runtime, off); | ||
2218 | if (substream->ops->copy) { | ||
2219 | if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0) | ||
2220 | return err; | ||
2221 | } else { | 2135 | } else { |
2222 | char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff); | 2136 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) |
2223 | if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames))) | 2137 | return -EINVAL; |
2224 | return -EFAULT; | 2138 | writer = noninterleaved_copy; |
2225 | } | 2139 | } |
2226 | return 0; | ||
2227 | } | ||
2228 | 2140 | ||
2229 | static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | 2141 | if (!data) { |
2230 | unsigned long data, | 2142 | if (is_playback) |
2231 | snd_pcm_uframes_t size, | 2143 | transfer = fill_silence; |
2232 | int nonblock, | 2144 | else |
2233 | transfer_f transfer) | 2145 | return -EINVAL; |
2234 | { | 2146 | } else if (in_kernel) { |
2235 | struct snd_pcm_runtime *runtime = substream->runtime; | 2147 | if (substream->ops->copy_kernel) |
2236 | snd_pcm_uframes_t xfer = 0; | 2148 | transfer = substream->ops->copy_kernel; |
2237 | snd_pcm_uframes_t offset = 0; | 2149 | else |
2238 | snd_pcm_uframes_t avail; | 2150 | transfer = is_playback ? |
2239 | int err = 0; | 2151 | default_write_copy_kernel : default_read_copy_kernel; |
2152 | } else { | ||
2153 | if (substream->ops->copy_user) | ||
2154 | transfer = (pcm_transfer_f)substream->ops->copy_user; | ||
2155 | else | ||
2156 | transfer = is_playback ? | ||
2157 | default_write_copy : default_read_copy; | ||
2158 | } | ||
2240 | 2159 | ||
2241 | if (size == 0) | 2160 | if (size == 0) |
2242 | return 0; | 2161 | return 0; |
2243 | 2162 | ||
2163 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2164 | |||
2244 | snd_pcm_stream_lock_irq(substream); | 2165 | snd_pcm_stream_lock_irq(substream); |
2245 | switch (runtime->status->state) { | 2166 | err = pcm_accessible_state(runtime); |
2246 | case SNDRV_PCM_STATE_PREPARED: | 2167 | if (err < 0) |
2247 | if (size >= runtime->start_threshold) { | ||
2248 | err = snd_pcm_start(substream); | ||
2249 | if (err < 0) | ||
2250 | goto _end_unlock; | ||
2251 | } | ||
2252 | break; | ||
2253 | case SNDRV_PCM_STATE_DRAINING: | ||
2254 | case SNDRV_PCM_STATE_RUNNING: | ||
2255 | case SNDRV_PCM_STATE_PAUSED: | ||
2256 | break; | ||
2257 | case SNDRV_PCM_STATE_XRUN: | ||
2258 | err = -EPIPE; | ||
2259 | goto _end_unlock; | ||
2260 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2261 | err = -ESTRPIPE; | ||
2262 | goto _end_unlock; | ||
2263 | default: | ||
2264 | err = -EBADFD; | ||
2265 | goto _end_unlock; | 2168 | goto _end_unlock; |
2169 | |||
2170 | if (!is_playback && | ||
2171 | runtime->status->state == SNDRV_PCM_STATE_PREPARED && | ||
2172 | size >= runtime->start_threshold) { | ||
2173 | err = snd_pcm_start(substream); | ||
2174 | if (err < 0) | ||
2175 | goto _end_unlock; | ||
2266 | } | 2176 | } |
2267 | 2177 | ||
2268 | runtime->twake = runtime->control->avail_min ? : 1; | 2178 | runtime->twake = runtime->control->avail_min ? : 1; |
2269 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 2179 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
2270 | snd_pcm_update_hw_ptr(substream); | 2180 | snd_pcm_update_hw_ptr(substream); |
2271 | avail = snd_pcm_capture_avail(runtime); | 2181 | if (is_playback) |
2182 | avail = snd_pcm_playback_avail(runtime); | ||
2183 | else | ||
2184 | avail = snd_pcm_capture_avail(runtime); | ||
2272 | while (size > 0) { | 2185 | while (size > 0) { |
2273 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2186 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
2274 | snd_pcm_uframes_t cont; | 2187 | snd_pcm_uframes_t cont; |
2275 | if (!avail) { | 2188 | if (!avail) { |
2276 | if (runtime->status->state == | 2189 | if (!is_playback && |
2277 | SNDRV_PCM_STATE_DRAINING) { | 2190 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
2278 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | 2191 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); |
2279 | goto _end_unlock; | 2192 | goto _end_unlock; |
2280 | } | 2193 | } |
@@ -2291,7 +2204,9 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2291 | continue; /* draining */ | 2204 | continue; /* draining */ |
2292 | } | 2205 | } |
2293 | frames = size > avail ? avail : size; | 2206 | frames = size > avail ? avail : size; |
2294 | cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; | 2207 | appl_ptr = READ_ONCE(runtime->control->appl_ptr); |
2208 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2209 | cont = runtime->buffer_size - appl_ofs; | ||
2295 | if (frames > cont) | 2210 | if (frames > cont) |
2296 | frames = cont; | 2211 | frames = cont; |
2297 | if (snd_BUG_ON(!frames)) { | 2212 | if (snd_BUG_ON(!frames)) { |
@@ -2299,34 +2214,33 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2299 | snd_pcm_stream_unlock_irq(substream); | 2214 | snd_pcm_stream_unlock_irq(substream); |
2300 | return -EINVAL; | 2215 | return -EINVAL; |
2301 | } | 2216 | } |
2302 | appl_ptr = runtime->control->appl_ptr; | ||
2303 | appl_ofs = appl_ptr % runtime->buffer_size; | ||
2304 | snd_pcm_stream_unlock_irq(substream); | 2217 | snd_pcm_stream_unlock_irq(substream); |
2305 | err = transfer(substream, appl_ofs, data, offset, frames); | 2218 | err = writer(substream, appl_ofs, data, offset, frames, |
2219 | transfer); | ||
2306 | snd_pcm_stream_lock_irq(substream); | 2220 | snd_pcm_stream_lock_irq(substream); |
2307 | if (err < 0) | 2221 | if (err < 0) |
2308 | goto _end_unlock; | 2222 | goto _end_unlock; |
2309 | switch (runtime->status->state) { | 2223 | err = pcm_accessible_state(runtime); |
2310 | case SNDRV_PCM_STATE_XRUN: | 2224 | if (err < 0) |
2311 | err = -EPIPE; | ||
2312 | goto _end_unlock; | ||
2313 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2314 | err = -ESTRPIPE; | ||
2315 | goto _end_unlock; | 2225 | goto _end_unlock; |
2316 | default: | ||
2317 | break; | ||
2318 | } | ||
2319 | appl_ptr += frames; | 2226 | appl_ptr += frames; |
2320 | if (appl_ptr >= runtime->boundary) | 2227 | if (appl_ptr >= runtime->boundary) |
2321 | appl_ptr -= runtime->boundary; | 2228 | appl_ptr -= runtime->boundary; |
2322 | runtime->control->appl_ptr = appl_ptr; | 2229 | err = pcm_lib_apply_appl_ptr(substream, appl_ptr); |
2323 | if (substream->ops->ack) | 2230 | if (err < 0) |
2324 | substream->ops->ack(substream); | 2231 | goto _end_unlock; |
2325 | 2232 | ||
2326 | offset += frames; | 2233 | offset += frames; |
2327 | size -= frames; | 2234 | size -= frames; |
2328 | xfer += frames; | 2235 | xfer += frames; |
2329 | avail -= frames; | 2236 | avail -= frames; |
2237 | if (is_playback && | ||
2238 | runtime->status->state == SNDRV_PCM_STATE_PREPARED && | ||
2239 | snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { | ||
2240 | err = snd_pcm_start(substream); | ||
2241 | if (err < 0) | ||
2242 | goto _end_unlock; | ||
2243 | } | ||
2330 | } | 2244 | } |
2331 | _end_unlock: | 2245 | _end_unlock: |
2332 | runtime->twake = 0; | 2246 | runtime->twake = 0; |
@@ -2335,83 +2249,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
2335 | snd_pcm_stream_unlock_irq(substream); | 2249 | snd_pcm_stream_unlock_irq(substream); |
2336 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2250 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
2337 | } | 2251 | } |
2338 | 2252 | EXPORT_SYMBOL(__snd_pcm_lib_xfer); | |
2339 | snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size) | ||
2340 | { | ||
2341 | struct snd_pcm_runtime *runtime; | ||
2342 | int nonblock; | ||
2343 | int err; | ||
2344 | |||
2345 | err = pcm_sanity_check(substream); | ||
2346 | if (err < 0) | ||
2347 | return err; | ||
2348 | runtime = substream->runtime; | ||
2349 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2350 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED) | ||
2351 | return -EINVAL; | ||
2352 | return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer); | ||
2353 | } | ||
2354 | |||
2355 | EXPORT_SYMBOL(snd_pcm_lib_read); | ||
2356 | |||
2357 | static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream, | ||
2358 | unsigned int hwoff, | ||
2359 | unsigned long data, unsigned int off, | ||
2360 | snd_pcm_uframes_t frames) | ||
2361 | { | ||
2362 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2363 | int err; | ||
2364 | void __user **bufs = (void __user **)data; | ||
2365 | int channels = runtime->channels; | ||
2366 | int c; | ||
2367 | if (substream->ops->copy) { | ||
2368 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2369 | char __user *buf; | ||
2370 | if (*bufs == NULL) | ||
2371 | continue; | ||
2372 | buf = *bufs + samples_to_bytes(runtime, off); | ||
2373 | if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0) | ||
2374 | return err; | ||
2375 | } | ||
2376 | } else { | ||
2377 | snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels; | ||
2378 | for (c = 0; c < channels; ++c, ++bufs) { | ||
2379 | char *hwbuf; | ||
2380 | char __user *buf; | ||
2381 | if (*bufs == NULL) | ||
2382 | continue; | ||
2383 | |||
2384 | hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff); | ||
2385 | buf = *bufs + samples_to_bytes(runtime, off); | ||
2386 | if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames))) | ||
2387 | return -EFAULT; | ||
2388 | } | ||
2389 | } | ||
2390 | return 0; | ||
2391 | } | ||
2392 | |||
2393 | snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream, | ||
2394 | void __user **bufs, | ||
2395 | snd_pcm_uframes_t frames) | ||
2396 | { | ||
2397 | struct snd_pcm_runtime *runtime; | ||
2398 | int nonblock; | ||
2399 | int err; | ||
2400 | |||
2401 | err = pcm_sanity_check(substream); | ||
2402 | if (err < 0) | ||
2403 | return err; | ||
2404 | runtime = substream->runtime; | ||
2405 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2406 | return -EBADFD; | ||
2407 | |||
2408 | nonblock = !!(substream->f_flags & O_NONBLOCK); | ||
2409 | if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | ||
2410 | return -EINVAL; | ||
2411 | return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer); | ||
2412 | } | ||
2413 | |||
2414 | EXPORT_SYMBOL(snd_pcm_lib_readv); | ||
2415 | 2253 | ||
2416 | /* | 2254 | /* |
2417 | * standard channel mapping helpers | 2255 | * standard channel mapping helpers |