Blame view

include/sound/pcm-indirect.h 5.04 KB
74ba9207e   Thomas Gleixner   treewide: Replace...
1
  /* SPDX-License-Identifier: GPL-2.0-or-later */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
  /*
   * Helper functions for indirect PCM data transfer
   *
   *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
6
   *                   Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
   */
  
  #ifndef __SOUND_PCM_INDIRECT_H
  #define __SOUND_PCM_INDIRECT_H
  
  #include <sound/pcm.h>
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
13
  struct snd_pcm_indirect {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
22
23
  	unsigned int hw_buffer_size;	/* Byte size of hardware buffer */
  	unsigned int hw_queue_size;	/* Max queue size of hw buffer (0 = buffer size) */
  	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
  	unsigned int hw_io;	/* Ring buffer hw pointer */
  	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
  	unsigned int sw_buffer_size;	/* Byte size of software buffer */
  	unsigned int sw_data;	/* Offset to next dst (or src) in sw ring buffer */
  	unsigned int sw_io;	/* Current software pointer in bytes */
  	int sw_ready;		/* Bytes ready to be transferred to/from hw */
  	snd_pcm_uframes_t appl_ptr;	/* Last seen appl_ptr */
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
24
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25

877211f5e   Takashi Iwai   [ALSA] Remove xxx...
26
27
  typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
  					struct snd_pcm_indirect *rec, size_t bytes);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
  
  /*
   * helper function for playback ack callback
   */
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
32
  static inline int
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
33
34
  snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
  				   struct snd_pcm_indirect *rec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  				   snd_pcm_indirect_copy_t copy)
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
37
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
  	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
  	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
  	int qsize;
  
  	if (diff) {
  		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
  			diff += runtime->boundary;
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
45
46
  		if (diff < 0)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
  		rec->appl_ptr = appl_ptr;
  	}
  	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
  	while (rec->hw_ready < qsize && rec->sw_ready > 0) {
  		unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
  		unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
  		unsigned int bytes = qsize - rec->hw_ready;
  		if (rec->sw_ready < (int)bytes)
  			bytes = rec->sw_ready;
  		if (hw_to_end < bytes)
  			bytes = hw_to_end;
  		if (sw_to_end < bytes)
  			bytes = sw_to_end;
  		if (! bytes)
  			break;
  		copy(substream, rec, bytes);
  		rec->hw_data += bytes;
  		if (rec->hw_data == rec->hw_buffer_size)
  			rec->hw_data = 0;
  		rec->sw_data += bytes;
  		if (rec->sw_data == rec->sw_buffer_size)
  			rec->sw_data = 0;
  		rec->hw_ready += bytes;
  		rec->sw_ready -= bytes;
  	}
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
73
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
75
76
77
78
79
80
  }
  
  /*
   * helper function for playback pointer callback
   * ptr = current byte pointer
   */
  static inline snd_pcm_uframes_t
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
81
82
  snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
  				  struct snd_pcm_indirect *rec, unsigned int ptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  {
  	int bytes = ptr - rec->hw_io;
  	if (bytes < 0)
  		bytes += rec->hw_buffer_size;
  	rec->hw_io = ptr;
  	rec->hw_ready -= bytes;
  	rec->sw_io += bytes;
  	if (rec->sw_io >= rec->sw_buffer_size)
  		rec->sw_io -= rec->sw_buffer_size;
  	if (substream->ops->ack)
  		substream->ops->ack(substream);
  	return bytes_to_frames(substream->runtime, rec->sw_io);
  }
  
  
  /*
   * helper function for capture ack callback
   */
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
101
  static inline int
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
102
103
  snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
  				  struct snd_pcm_indirect *rec,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
  				  snd_pcm_indirect_copy_t copy)
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
106
  	struct snd_pcm_runtime *runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
111
112
  	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
  	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
  
  	if (diff) {
  		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
  			diff += runtime->boundary;
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
113
114
  		if (diff < 0)
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  		rec->sw_ready -= frames_to_bytes(runtime, diff);
  		rec->appl_ptr = appl_ptr;
  	}
  	while (rec->hw_ready > 0 && 
  	       rec->sw_ready < (int)rec->sw_buffer_size) {
  		size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
  		size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
  		size_t bytes = rec->sw_buffer_size - rec->sw_ready;
  		if (rec->hw_ready < (int)bytes)
  			bytes = rec->hw_ready;
  		if (hw_to_end < bytes)
  			bytes = hw_to_end;
  		if (sw_to_end < bytes)
  			bytes = sw_to_end;
  		if (! bytes)
  			break;
  		copy(substream, rec, bytes);
  		rec->hw_data += bytes;
  		if ((int)rec->hw_data == rec->hw_buffer_size)
  			rec->hw_data = 0;
  		rec->sw_data += bytes;
  		if (rec->sw_data == rec->sw_buffer_size)
  			rec->sw_data = 0;
  		rec->hw_ready -= bytes;
  		rec->sw_ready += bytes;
  	}
962958125   Takashi Iwai   ALSA: pcm: Fix ne...
141
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
147
148
  }
  
  /*
   * helper function for capture pointer callback,
   * ptr = current byte pointer
   */
  static inline snd_pcm_uframes_t
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
149
150
  snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
  				 struct snd_pcm_indirect *rec, unsigned int ptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  {
  	int qsize;
  	int bytes = ptr - rec->hw_io;
  	if (bytes < 0)
  		bytes += rec->hw_buffer_size;
  	rec->hw_io = ptr;
  	rec->hw_ready += bytes;
  	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
  	if (rec->hw_ready > qsize)
  		return SNDRV_PCM_POS_XRUN;
  	rec->sw_io += bytes;
  	if (rec->sw_io >= rec->sw_buffer_size)
  		rec->sw_io -= rec->sw_buffer_size;
  	if (substream->ops->ack)
  		substream->ops->ack(substream);
  	return bytes_to_frames(substream->runtime, rec->sw_io);
  }
  
  #endif /* __SOUND_PCM_INDIRECT_H */