Linux Audio

Check our new training course

Loading...
v3.1
 
  1/*
  2 * Helper functions for indirect PCM data transfer
  3 *
  4 *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
  5 *                   Jaroslav Kysela <perex@perex.cz>
  6 *
  7 *   This program is free software; you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation; either version 2 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   This program is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with this program; if not, write to the Free Software
 19 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 20 */
 21
 22#ifndef __SOUND_PCM_INDIRECT_H
 23#define __SOUND_PCM_INDIRECT_H
 24
 25#include <sound/pcm.h>
 26
 27struct snd_pcm_indirect {
 28	unsigned int hw_buffer_size;	/* Byte size of hardware buffer */
 29	unsigned int hw_queue_size;	/* Max queue size of hw buffer (0 = buffer size) */
 30	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
 31	unsigned int hw_io;	/* Ring buffer hw pointer */
 32	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
 33	unsigned int sw_buffer_size;	/* Byte size of software buffer */
 34	unsigned int sw_data;	/* Offset to next dst (or src) in sw ring buffer */
 35	unsigned int sw_io;	/* Current software pointer in bytes */
 36	int sw_ready;		/* Bytes ready to be transferred to/from hw */
 37	snd_pcm_uframes_t appl_ptr;	/* Last seen appl_ptr */
 38};
 39
 40typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
 41					struct snd_pcm_indirect *rec, size_t bytes);
 42
 43/*
 44 * helper function for playback ack callback
 45 */
 46static inline void
 47snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 48				   struct snd_pcm_indirect *rec,
 49				   snd_pcm_indirect_copy_t copy)
 50{
 51	struct snd_pcm_runtime *runtime = substream->runtime;
 52	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 53	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
 54	int qsize;
 55
 56	if (diff) {
 57		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 58			diff += runtime->boundary;
 
 
 59		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
 60		rec->appl_ptr = appl_ptr;
 61	}
 62	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
 63	while (rec->hw_ready < qsize && rec->sw_ready > 0) {
 64		unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
 65		unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
 66		unsigned int bytes = qsize - rec->hw_ready;
 67		if (rec->sw_ready < (int)bytes)
 68			bytes = rec->sw_ready;
 69		if (hw_to_end < bytes)
 70			bytes = hw_to_end;
 71		if (sw_to_end < bytes)
 72			bytes = sw_to_end;
 73		if (! bytes)
 74			break;
 75		copy(substream, rec, bytes);
 76		rec->hw_data += bytes;
 77		if (rec->hw_data == rec->hw_buffer_size)
 78			rec->hw_data = 0;
 79		rec->sw_data += bytes;
 80		if (rec->sw_data == rec->sw_buffer_size)
 81			rec->sw_data = 0;
 82		rec->hw_ready += bytes;
 83		rec->sw_ready -= bytes;
 84	}
 
 85}
 86
 87/*
 88 * helper function for playback pointer callback
 89 * ptr = current byte pointer
 90 */
 91static inline snd_pcm_uframes_t
 92snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
 93				  struct snd_pcm_indirect *rec, unsigned int ptr)
 94{
 95	int bytes = ptr - rec->hw_io;
 96	if (bytes < 0)
 97		bytes += rec->hw_buffer_size;
 98	rec->hw_io = ptr;
 99	rec->hw_ready -= bytes;
100	rec->sw_io += bytes;
101	if (rec->sw_io >= rec->sw_buffer_size)
102		rec->sw_io -= rec->sw_buffer_size;
103	if (substream->ops->ack)
104		substream->ops->ack(substream);
105	return bytes_to_frames(substream->runtime, rec->sw_io);
106}
107
108
109/*
110 * helper function for capture ack callback
111 */
112static inline void
113snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
114				  struct snd_pcm_indirect *rec,
115				  snd_pcm_indirect_copy_t copy)
116{
117	struct snd_pcm_runtime *runtime = substream->runtime;
118	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
119	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
120
121	if (diff) {
122		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
123			diff += runtime->boundary;
 
 
124		rec->sw_ready -= frames_to_bytes(runtime, diff);
125		rec->appl_ptr = appl_ptr;
126	}
127	while (rec->hw_ready > 0 && 
128	       rec->sw_ready < (int)rec->sw_buffer_size) {
129		size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
130		size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
131		size_t bytes = rec->sw_buffer_size - rec->sw_ready;
132		if (rec->hw_ready < (int)bytes)
133			bytes = rec->hw_ready;
134		if (hw_to_end < bytes)
135			bytes = hw_to_end;
136		if (sw_to_end < bytes)
137			bytes = sw_to_end;
138		if (! bytes)
139			break;
140		copy(substream, rec, bytes);
141		rec->hw_data += bytes;
142		if ((int)rec->hw_data == rec->hw_buffer_size)
143			rec->hw_data = 0;
144		rec->sw_data += bytes;
145		if (rec->sw_data == rec->sw_buffer_size)
146			rec->sw_data = 0;
147		rec->hw_ready -= bytes;
148		rec->sw_ready += bytes;
149	}
 
150}
151
152/*
153 * helper function for capture pointer callback,
154 * ptr = current byte pointer
155 */
156static inline snd_pcm_uframes_t
157snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
158				 struct snd_pcm_indirect *rec, unsigned int ptr)
159{
160	int qsize;
161	int bytes = ptr - rec->hw_io;
162	if (bytes < 0)
163		bytes += rec->hw_buffer_size;
164	rec->hw_io = ptr;
165	rec->hw_ready += bytes;
166	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
167	if (rec->hw_ready > qsize)
168		return SNDRV_PCM_POS_XRUN;
169	rec->sw_io += bytes;
170	if (rec->sw_io >= rec->sw_buffer_size)
171		rec->sw_io -= rec->sw_buffer_size;
172	if (substream->ops->ack)
173		substream->ops->ack(substream);
174	return bytes_to_frames(substream->runtime, rec->sw_io);
175}
176
177#endif /* __SOUND_PCM_INDIRECT_H */
v6.2
  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
 14struct 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
 27typedef 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 */
 33static inline int
 34snd_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 */
 81static inline snd_pcm_uframes_t
 82snd_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 */
102static inline int
103snd_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 */
149static inline snd_pcm_uframes_t
150snd_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 */