<?xml version="1.0" encoding="ANSI_X3.4-1968" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=ANSI_X3.4-1968" /><title>External Hardware Buffers</title><meta name="generator" content="DocBook XSL Stylesheets V1.76.1" /><link rel="home" href="index.html" title="Writing an ALSA Driver" /><link rel="up" href="buffer-and-memory.html" title="Chapter 11. Buffer and Memory Management" /><link rel="prev" href="buffer-and-memory.html" title="Chapter 11. Buffer and Memory Management" /><link rel="next" href="buffer-and-memory-non-contiguous.html" title="Non-Contiguous Buffers" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">External Hardware Buffers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="buffer-and-memory.html">Prev</a> </td><th width="60%" align="center">Chapter 11. Buffer and Memory Management</th><td width="20%" align="right"> <a accesskey="n" href="buffer-and-memory-non-contiguous.html">Next</a></td></tr></table><hr /></div><div class="section" title="External Hardware Buffers"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="buffer-and-memory-external-hardware"></a>External Hardware Buffers</h2></div></div></div><p> Some chips have their own hardware buffers and the DMA transfer from the host memory is not available. In such a case, you need to either 1) copy/set the audio data directly to the external hardware buffer, or 2) make an intermediate buffer and copy/set the data from it to the external hardware buffer in interrupts (or in tasklets, preferably). </p><p> 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 effective. You need to define the <em class="structfield"><code>copy</code></em> and <em class="structfield"><code>silence</code></em> callbacks for the data transfer. However, there is a drawback: it cannot be mmapped. The examples are GUS's GF1 PCM or emu8000's wavetable PCM. </p><p> The second case allows for mmap on the buffer, although you have to handle an interrupt or a tasklet to transfer the data from the intermediate buffer to the hardware buffer. You can find an example in the vxpocket driver. </p><p> 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 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 <em class="structfield"><code>copy</code></em> and <em class="structfield"><code>silence</code></em> callbacks as well, as in the cases above. The examples are found in <code class="filename">rme32.c</code> and <code class="filename">rme96.c</code>. </p><p> The implementation of the <em class="structfield"><code>copy</code></em> and <em class="structfield"><code>silence</code></em> callbacks depends upon whether the hardware supports interleaved or non-interleaved samples. The <em class="structfield"><code>copy</code></em> callback is defined like below, a bit differently depending whether the direction is playback or capture: </p><div class="informalexample"><pre class="programlisting"> static int playback_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void *src, snd_pcm_uframes_t count); static int capture_copy(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void *dst, snd_pcm_uframes_t count); </pre></div><p> </p><p> In the case of interleaved samples, the second argument (<em class="parameter"><code>channel</code></em>) is not used. The third argument (<em class="parameter"><code>pos</code></em>) points the current position offset in frames. </p><p> The meaning of the fourth argument is different between playback and capture. For playback, it holds the source data pointer, and for capture, it's the destination data pointer. </p><p> The last argument is the number of frames to be copied. </p><p> 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 of data (<em class="parameter"><code>count</code></em>) at the specified pointer (<em class="parameter"><code>src</code></em>) to the specified offset (<em class="parameter"><code>pos</code></em>) on the hardware buffer. When coded like memcpy-like way, the copy would be like: </p><div class="informalexample"><pre class="programlisting"> my_memcpy(my_buffer + frames_to_bytes(runtime, pos), src, frames_to_bytes(runtime, count)); </pre></div><p> </p><p> For the capture direction, you copy the given amount of data (<em class="parameter"><code>count</code></em>) at the specified offset (<em class="parameter"><code>pos</code></em>) on the hardware buffer to the specified pointer (<em class="parameter"><code>dst</code></em>). </p><div class="informalexample"><pre class="programlisting"> my_memcpy(dst, my_buffer + frames_to_bytes(runtime, pos), frames_to_bytes(runtime, count)); </pre></div><p> Note that both the position and the amount of data are given in frames. </p><p> In the case of non-interleaved samples, the implementation will be a bit more complicated. </p><p> You need to check the channel argument, and if it's -1, copy the whole channels. Otherwise, you have to copy only the specified channel. Please check <code class="filename">isa/gus/gus_pcm.c</code> as an example. </p><p> The <em class="structfield"><code>silence</code></em> callback is also implemented in a similar way. </p><div class="informalexample"><pre class="programlisting"> static int silence(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count); </pre></div><p> </p><p> The meanings of arguments are the same as in the <em class="structfield"><code>copy</code></em> callback, although there is no <em class="parameter"><code>src/dst</code></em> argument. In the case of interleaved samples, the channel argument has no meaning, as well as on <em class="structfield"><code>copy</code></em> callback. </p><p> The role of <em class="structfield"><code>silence</code></em> callback is to set the given amount (<em class="parameter"><code>count</code></em>) of silence data at the specified offset (<em class="parameter"><code>pos</code></em>) on 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 would be like: </p><div class="informalexample"><pre class="programlisting"> my_memcpy(my_buffer + frames_to_bytes(runtime, pos), 0, frames_to_bytes(runtime, count)); </pre></div><p> </p><p> In the case of non-interleaved samples, again, the implementation becomes a bit more complicated. See, for example, <code class="filename">isa/gus/gus_pcm.c</code>. </p></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="buffer-and-memory.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="buffer-and-memory.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="buffer-and-memory-non-contiguous.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 11. Buffer and Memory Management </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Non-Contiguous Buffers</td></tr></table></div></body></html>