ALSA: doc: Update copy_user, copy_kernel and fill_silence PCM ops

Reviewed-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2017-06-01 22:36:02 +02:00
Родитель fed5794fcc
Коммит f7a478178a
1 изменённых файлов: 76 добавлений и 35 удалений

Просмотреть файл

@ -2080,8 +2080,8 @@ sleeping poll threads, etc.
This callback is also atomic as default. This callback is also atomic as default.
copy and silence callbacks copy_user, copy_kernel and fill_silence ops
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These callbacks are not mandatory, and can be omitted in most cases. These callbacks are not mandatory, and can be omitted in most cases.
These callbacks are used when the hardware buffer cannot be in the These callbacks are used when the hardware buffer cannot be in the
@ -3532,8 +3532,9 @@ external hardware buffer in interrupts (or in tasklets, preferably).
The first case works fine if the external hardware buffer is large The first case works fine if the external hardware buffer is large
enough. This method doesn't need any extra buffers and thus is more enough. This method doesn't need any extra buffers and thus is more
effective. You need to define the ``copy`` and ``silence`` callbacks effective. You need to define the ``copy_user`` and ``copy_kernel``
for the data transfer. However, there is a drawback: it cannot be callbacks for the data transfer, in addition to ``fill_silence``
callback for playback. However, there is a drawback: it cannot be
mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM. mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM.
The second case allows for mmap on the buffer, although you have to The second case allows for mmap on the buffer, although you have to
@ -3545,30 +3546,34 @@ Another case is when the chip uses a PCI memory-map region for the
buffer instead of the host memory. In this case, mmap is available only buffer instead of the host memory. In this case, mmap is available only
on certain architectures like the Intel one. In non-mmap mode, the data on certain architectures like the Intel one. In non-mmap mode, the data
cannot be transferred as in the normal way. Thus you need to define the cannot be transferred as in the normal way. Thus you need to define the
``copy`` and ``silence`` callbacks as well, as in the cases above. The ``copy_user``, ``copy_kernel`` and ``fill_silence`` callbacks as well,
examples are found in ``rme32.c`` and ``rme96.c``. as in the cases above. The examples are found in ``rme32.c`` and
``rme96.c``.
The implementation of the ``copy`` and ``silence`` callbacks depends The implementation of the ``copy_user``, ``copy_kernel`` and
upon whether the hardware supports interleaved or non-interleaved ``silence`` callbacks depends upon whether the hardware supports
samples. The ``copy`` callback is defined like below, a bit interleaved or non-interleaved samples. The ``copy_user`` callback is
differently depending whether the direction is playback or capture: defined like below, a bit differently depending whether the direction
is playback or capture:
:: ::
static int playback_copy(struct snd_pcm_substream *substream, int channel, static int playback_copy_user(struct snd_pcm_substream *substream,
snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count); int channel, unsigned long pos,
static int capture_copy(struct snd_pcm_substream *substream, int channel, void __user *src, unsigned long count);
snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count); static int capture_copy_user(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void __user *dst, unsigned long count);
In the case of interleaved samples, the second argument (``channel``) is In the case of interleaved samples, the second argument (``channel``) is
not used. The third argument (``pos``) points the current position not used. The third argument (``pos``) points the current position
offset in frames. offset in bytes.
The meaning of the fourth argument is different between playback and The meaning of the fourth argument is different between playback and
capture. For playback, it holds the source data pointer, and for capture. For playback, it holds the source data pointer, and for
capture, it's the destination data pointer. capture, it's the destination data pointer.
The last argument is the number of frames to be copied. The last argument is the number of bytes to be copied.
What you have to do in this callback is again different between playback What you have to do in this callback is again different between playback
and capture directions. In the playback case, you copy the given amount and capture directions. In the playback case, you copy the given amount
@ -3578,8 +3583,7 @@ way, the copy would be like:
:: ::
my_memcpy(my_buffer + frames_to_bytes(runtime, pos), src, my_memcpy_from_user(my_buffer + pos, src, count);
frames_to_bytes(runtime, count));
For the capture direction, you copy the given amount of data (``count``) For the capture direction, you copy the given amount of data (``count``)
at the specified offset (``pos``) on the hardware buffer to the at the specified offset (``pos``) on the hardware buffer to the
@ -3587,31 +3591,68 @@ specified pointer (``dst``).
:: ::
my_memcpy(dst, my_buffer + frames_to_bytes(runtime, pos), my_memcpy_to_user(dst, my_buffer + pos, count);
frames_to_bytes(runtime, count));
Note that both the position and the amount of data are given in frames. Here the functions are named as ``from_user`` and ``to_user`` because
it's the user-space buffer that is passed to these callbacks. That
is, the callback is supposed to copy from/to the user-space data
directly to/from the hardware buffer.
Careful readers might notice that these callbacks receive the
arguments in bytes, not in frames like other callbacks. It's because
it would make coding easier like the examples above, and also it makes
easier to unify both the interleaved and non-interleaved cases, as
explained in the following.
In the case of non-interleaved samples, the implementation will be a bit In the case of non-interleaved samples, the implementation will be a bit
more complicated. more complicated. The callback is called for each channel, passed by
the second argument, so totally it's called for N-channels times per
transfer.
You need to check the channel argument, and if it's -1, copy the whole The meaning of other arguments are almost same as the interleaved
channels. Otherwise, you have to copy only the specified channel. Please case. The callback is supposed to copy the data from/to the given
check ``isa/gus/gus_pcm.c`` as an example. user-space buffer, but only for the given channel. For the detailed
implementations, please check ``isa/gus/gus_pcm.c`` or
"pci/rme9652/rme9652.c" as examples.
The ``silence`` callback is also implemented in a similar way The above callbacks are the copy from/to the user-space buffer. There
are some cases where we want copy from/to the kernel-space buffer
instead. In such a case, ``copy_kernel`` callback is called. It'd
look like:
::
static int playback_copy_kernel(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void *src, unsigned long count);
static int capture_copy_kernel(struct snd_pcm_substream *substream,
int channel, unsigned long pos,
void *dst, unsigned long count);
As found easily, the only difference is that the buffer pointer is
without ``__user`` prefix; that is, a kernel-buffer pointer is passed
in the fourth argument. Correspondingly, the implementation would be
a version without the user-copy, such as:
::
my_memcpy(my_buffer + pos, src, count);
Usually for the playback, another callback ``fill_silence`` is
defined. It's implemented in a similar way as the copy callbacks
above:
:: ::
static int silence(struct snd_pcm_substream *substream, int channel, static int silence(struct snd_pcm_substream *substream, int channel,
snd_pcm_uframes_t pos, snd_pcm_uframes_t count); unsigned long pos, unsigned long count);
The meanings of arguments are the same as in the ``copy`` callback, The meanings of arguments are the same as in the ``copy_user`` and
although there is no ``src/dst`` argument. In the case of interleaved ``copy_kernel`` callbacks, although there is no buffer pointer
samples, the channel argument has no meaning, as well as on ``copy`` argument. In the case of interleaved samples, the channel argument has
callback. no meaning, as well as on ``copy_*`` callbacks.
The role of ``silence`` callback is to set the given amount The role of ``fill_silence`` callback is to set the given amount
(``count``) of silence data at the specified offset (``pos``) on the (``count``) of silence data at the specified offset (``pos``) on the
hardware buffer. Suppose that the data format is signed (that is, the hardware buffer. Suppose that the data format is signed (that is, the
silent-data is 0), and the implementation using a memset-like function silent-data is 0), and the implementation using a memset-like function
@ -3619,11 +3660,11 @@ would be like:
:: ::
my_memcpy(my_buffer + frames_to_bytes(runtime, pos), 0, my_memset(my_buffer + pos, 0, count);
frames_to_bytes(runtime, count));
In the case of non-interleaved samples, again, the implementation In the case of non-interleaved samples, again, the implementation
becomes a bit more complicated. See, for example, ``isa/gus/gus_pcm.c``. becomes a bit more complicated, as it's called N-times per transfer
for each channel. See, for example, ``isa/gus/gus_pcm.c``.
Non-Contiguous Buffers Non-Contiguous Buffers
---------------------- ----------------------