root/include/sound/pcm-indirect.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. snd_pcm_indirect_playback_transfer
  2. snd_pcm_indirect_playback_pointer
  3. snd_pcm_indirect_capture_transfer
  4. snd_pcm_indirect_capture_pointer

   1 /* SPDX-License-Identifier: GPL-2.0-or-later */
   2 /*
   3  * Helper functions for indirect PCM data transfer
   4  *
   5  *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
   6  *                   Jaroslav Kysela <perex@perex.cz>
   7  */
   8 
   9 #ifndef __SOUND_PCM_INDIRECT_H
  10 #define __SOUND_PCM_INDIRECT_H
  11 
  12 #include <sound/pcm.h>
  13 
  14 struct snd_pcm_indirect {
  15         unsigned int hw_buffer_size;    /* Byte size of hardware buffer */
  16         unsigned int hw_queue_size;     /* Max queue size of hw buffer (0 = buffer size) */
  17         unsigned int hw_data;   /* Offset to next dst (or src) in hw ring buffer */
  18         unsigned int hw_io;     /* Ring buffer hw pointer */
  19         int hw_ready;           /* Bytes ready for play (or captured) in hw ring buffer */
  20         unsigned int sw_buffer_size;    /* Byte size of software buffer */
  21         unsigned int sw_data;   /* Offset to next dst (or src) in sw ring buffer */
  22         unsigned int sw_io;     /* Current software pointer in bytes */
  23         int sw_ready;           /* Bytes ready to be transferred to/from hw */
  24         snd_pcm_uframes_t appl_ptr;     /* Last seen appl_ptr */
  25 };
  26 
  27 typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
  28                                         struct snd_pcm_indirect *rec, size_t bytes);
  29 
  30 /*
  31  * helper function for playback ack callback
  32  */
  33 static inline int
  34 snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
  35                                    struct snd_pcm_indirect *rec,
  36                                    snd_pcm_indirect_copy_t copy)
  37 {
  38         struct snd_pcm_runtime *runtime = substream->runtime;
  39         snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
  40         snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
  41         int qsize;
  42 
  43         if (diff) {
  44                 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
  45                         diff += runtime->boundary;
  46                 if (diff < 0)
  47                         return -EINVAL;
  48                 rec->sw_ready += (int)frames_to_bytes(runtime, diff);
  49                 rec->appl_ptr = appl_ptr;
  50         }
  51         qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
  52         while (rec->hw_ready < qsize && rec->sw_ready > 0) {
  53                 unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
  54                 unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
  55                 unsigned int bytes = qsize - rec->hw_ready;
  56                 if (rec->sw_ready < (int)bytes)
  57                         bytes = rec->sw_ready;
  58                 if (hw_to_end < bytes)
  59                         bytes = hw_to_end;
  60                 if (sw_to_end < bytes)
  61                         bytes = sw_to_end;
  62                 if (! bytes)
  63                         break;
  64                 copy(substream, rec, bytes);
  65                 rec->hw_data += bytes;
  66                 if (rec->hw_data == rec->hw_buffer_size)
  67                         rec->hw_data = 0;
  68                 rec->sw_data += bytes;
  69                 if (rec->sw_data == rec->sw_buffer_size)
  70                         rec->sw_data = 0;
  71                 rec->hw_ready += bytes;
  72                 rec->sw_ready -= bytes;
  73         }
  74         return 0;
  75 }
  76 
  77 /*
  78  * helper function for playback pointer callback
  79  * ptr = current byte pointer
  80  */
  81 static inline snd_pcm_uframes_t
  82 snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
  83                                   struct snd_pcm_indirect *rec, unsigned int ptr)
  84 {
  85         int bytes = ptr - rec->hw_io;
  86         if (bytes < 0)
  87                 bytes += rec->hw_buffer_size;
  88         rec->hw_io = ptr;
  89         rec->hw_ready -= bytes;
  90         rec->sw_io += bytes;
  91         if (rec->sw_io >= rec->sw_buffer_size)
  92                 rec->sw_io -= rec->sw_buffer_size;
  93         if (substream->ops->ack)
  94                 substream->ops->ack(substream);
  95         return bytes_to_frames(substream->runtime, rec->sw_io);
  96 }
  97 
  98 
  99 /*
 100  * helper function for capture ack callback
 101  */
 102 static inline int
 103 snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
 104                                   struct snd_pcm_indirect *rec,
 105                                   snd_pcm_indirect_copy_t copy)
 106 {
 107         struct snd_pcm_runtime *runtime = substream->runtime;
 108         snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 109         snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
 110 
 111         if (diff) {
 112                 if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 113                         diff += runtime->boundary;
 114                 if (diff < 0)
 115                         return -EINVAL;
 116                 rec->sw_ready -= frames_to_bytes(runtime, diff);
 117                 rec->appl_ptr = appl_ptr;
 118         }
 119         while (rec->hw_ready > 0 && 
 120                rec->sw_ready < (int)rec->sw_buffer_size) {
 121                 size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
 122                 size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
 123                 size_t bytes = rec->sw_buffer_size - rec->sw_ready;
 124                 if (rec->hw_ready < (int)bytes)
 125                         bytes = rec->hw_ready;
 126                 if (hw_to_end < bytes)
 127                         bytes = hw_to_end;
 128                 if (sw_to_end < bytes)
 129                         bytes = sw_to_end;
 130                 if (! bytes)
 131                         break;
 132                 copy(substream, rec, bytes);
 133                 rec->hw_data += bytes;
 134                 if ((int)rec->hw_data == rec->hw_buffer_size)
 135                         rec->hw_data = 0;
 136                 rec->sw_data += bytes;
 137                 if (rec->sw_data == rec->sw_buffer_size)
 138                         rec->sw_data = 0;
 139                 rec->hw_ready -= bytes;
 140                 rec->sw_ready += bytes;
 141         }
 142         return 0;
 143 }
 144 
 145 /*
 146  * helper function for capture pointer callback,
 147  * ptr = current byte pointer
 148  */
 149 static inline snd_pcm_uframes_t
 150 snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
 151                                  struct snd_pcm_indirect *rec, unsigned int ptr)
 152 {
 153         int qsize;
 154         int bytes = ptr - rec->hw_io;
 155         if (bytes < 0)
 156                 bytes += rec->hw_buffer_size;
 157         rec->hw_io = ptr;
 158         rec->hw_ready += bytes;
 159         qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
 160         if (rec->hw_ready > qsize)
 161                 return SNDRV_PCM_POS_XRUN;
 162         rec->sw_io += bytes;
 163         if (rec->sw_io >= rec->sw_buffer_size)
 164                 rec->sw_io -= rec->sw_buffer_size;
 165         if (substream->ops->ack)
 166                 substream->ops->ack(substream);
 167         return bytes_to_frames(substream->runtime, rec->sw_io);
 168 }
 169 
 170 #endif /* __SOUND_PCM_INDIRECT_H */

/* [<][>][^][v][top][bottom][index][help] */