Sophie

Sophie

distrib > CentOS > 6 > i386 > by-pkgid > cf93d8a8acdcc6fe2225039da0502495 > files > 4179

kernel-doc-2.6.32-131.17.1.el6.centos.plus.noarch.rpm

<?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.75.2" /><link rel="home" href="index.html" title="Writing an ALSA Driver" /><link rel="up" href="ch11.html" title="Chapter&#160;11.&#160;Buffer and Memory Management" /><link rel="prev" href="ch11.html" title="Chapter&#160;11.&#160;Buffer and Memory Management" /><link rel="next" href="ch11s03.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="ch11.html">Prev</a>&#160;</td><th width="60%" align="center">Chapter&#160;11.&#160;Buffer and Memory Management</th><td width="20%" align="right">&#160;<a accesskey="n" href="ch11s03.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="ch11.html">Prev</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="ch11.html">Up</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="ch11s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&#160;11.&#160;Buffer and Memory Management&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&#160;Non-Contiguous Buffers</td></tr></table></div></body></html>