aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-12-08 10:10:44 -0500
committerTakashi Iwai <tiwai@suse.de>2014-12-10 04:48:12 -0500
commitf3699e2c77455a6cccc977b391c553f2c816f639 (patch)
tree3363d52b0c8eeb22f80c164bc30e25a52ac1f532 /sound/firewire
parent3c96101f190020e91d413c5835f7a722fc007923 (diff)
ALSA: oxfw: Change the way to start stream
In past commit, this driver can keep stream formations for each sampling rate. So its stream functionality can decide stream formations with given some parameters. This commit moves related codes from PCM functionality to stream functionality. Furthermore, to set stream format correctly, this commit uses AV/C Stream Format Information command instead of AV/C Input/Output Plug Signal Format command. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Acked-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire')
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c44
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c139
-rw-r--r--sound/firewire/oxfw/oxfw.h3
3 files changed, 138 insertions, 48 deletions
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
index 0c0be984edce..ea2b439253cf 100644
--- a/sound/firewire/oxfw/oxfw-pcm.c
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -166,39 +166,10 @@ static int pcm_hw_params(struct snd_pcm_substream *substream,
166 struct snd_pcm_hw_params *hw_params) 166 struct snd_pcm_hw_params *hw_params)
167{ 167{
168 struct snd_oxfw *oxfw = substream->private_data; 168 struct snd_oxfw *oxfw = substream->private_data;
169 int err;
170
171 mutex_lock(&oxfw->mutex);
172
173 snd_oxfw_stream_stop_simplex(oxfw);
174
175 err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
176 params_buffer_bytes(hw_params));
177 if (err < 0)
178 goto error;
179
180 amdtp_stream_set_parameters(&oxfw->rx_stream,
181 params_rate(hw_params),
182 params_channels(hw_params),
183 0);
184
185 amdtp_stream_set_pcm_format(&oxfw->rx_stream,
186 params_format(hw_params));
187
188 err = avc_general_set_sig_fmt(oxfw->unit, params_rate(hw_params),
189 AVC_GENERAL_PLUG_DIR_IN, 0);
190 if (err < 0) {
191 dev_err(&oxfw->unit->device, "failed to set sample rate\n");
192 goto err_buffer;
193 }
194 169
195 return 0; 170 amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
196 171 return snd_pcm_lib_alloc_vmalloc_buffer(substream,
197err_buffer: 172 params_buffer_bytes(hw_params));
198 snd_pcm_lib_free_vmalloc_buffer(substream);
199error:
200 mutex_unlock(&oxfw->mutex);
201 return err;
202} 173}
203 174
204static int pcm_hw_free(struct snd_pcm_substream *substream) 175static int pcm_hw_free(struct snd_pcm_substream *substream)
@@ -215,19 +186,18 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
215static int pcm_prepare(struct snd_pcm_substream *substream) 186static int pcm_prepare(struct snd_pcm_substream *substream)
216{ 187{
217 struct snd_oxfw *oxfw = substream->private_data; 188 struct snd_oxfw *oxfw = substream->private_data;
189 struct snd_pcm_runtime *runtime = substream->runtime;
218 int err; 190 int err;
219 191
220 mutex_lock(&oxfw->mutex); 192 mutex_lock(&oxfw->mutex);
221 193 err = snd_oxfw_stream_start_simplex(oxfw, runtime->rate,
222 snd_oxfw_stream_stop_simplex(oxfw); 194 runtime->channels);
223 195 mutex_unlock(&oxfw->mutex);
224 err = snd_oxfw_stream_start_simplex(oxfw);
225 if (err < 0) 196 if (err < 0)
226 goto end; 197 goto end;
227 198
228 amdtp_stream_pcm_prepare(&oxfw->rx_stream); 199 amdtp_stream_pcm_prepare(&oxfw->rx_stream);
229end: 200end:
230 mutex_unlock(&oxfw->mutex);
231 return err; 201 return err;
232} 202}
233 203
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
index 210bf5a2f56e..1820497f4bbf 100644
--- a/sound/firewire/oxfw/oxfw-stream.c
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -7,8 +7,10 @@
7 */ 7 */
8 8
9#include "oxfw.h" 9#include "oxfw.h"
10#include <linux/delay.h>
10 11
11#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512 12#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
13#define CALLBACK_TIMEOUT 200
12 14
13/* 15/*
14 * According to datasheet of Oxford Semiconductor: 16 * According to datasheet of Oxford Semiconductor:
@@ -37,6 +39,47 @@ static const unsigned int avc_stream_rate_table[] = {
37 [5] = 0x07, 39 [5] = 0x07,
38}; 40};
39 41
42static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
43 unsigned int rate, unsigned int pcm_channels)
44{
45 u8 **formats;
46 struct snd_oxfw_stream_formation formation;
47 enum avc_general_plug_dir dir;
48 unsigned int i, err, len;
49
50 formats = oxfw->rx_stream_formats;
51 dir = AVC_GENERAL_PLUG_DIR_IN;
52
53 /* Seek stream format for requirements. */
54 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
55 err = snd_oxfw_stream_parse_format(formats[i], &formation);
56 if (err < 0)
57 return err;
58
59 if ((formation.rate == rate) && (formation.pcm == pcm_channels))
60 break;
61 }
62 if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
63 return -EINVAL;
64
65 /* If assumed, just change rate. */
66 if (oxfw->assumed)
67 return avc_general_set_sig_fmt(oxfw->unit, rate,
68 AVC_GENERAL_PLUG_DIR_IN, 0);
69
70 /* Calculate format length. */
71 len = 5 + formats[i][4] * 2;
72
73 err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
74 if (err < 0)
75 return err;
76
77 /* Some requests just after changing format causes freezing. */
78 msleep(100);
79
80 return 0;
81}
82
40int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw) 83int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw)
41{ 84{
42 int err; 85 int err;
@@ -63,30 +106,106 @@ static void stop_stream(struct snd_oxfw *oxfw)
63 cmp_connection_break(&oxfw->in_conn); 106 cmp_connection_break(&oxfw->in_conn);
64} 107}
65 108
66int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw) 109static int start_stream(struct snd_oxfw *oxfw, unsigned int rate,
110 unsigned int pcm_channels)
67{ 111{
68 int err = 0; 112 u8 **formats;
113 struct cmp_connection *conn;
114 struct snd_oxfw_stream_formation formation;
115 unsigned int i, midi_ports;
116 struct amdtp_stream *stream;
117 int err;
69 118
70 if (amdtp_streaming_error(&oxfw->rx_stream)) 119 stream = &oxfw->rx_stream;
71 stop_stream(oxfw); 120 formats = oxfw->rx_stream_formats;
121 conn = &oxfw->in_conn;
72 122
73 if (amdtp_stream_running(&oxfw->rx_stream)) 123 /* Get stream formation */
124 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
125 if (formats[i] == NULL)
126 break;
127
128 err = snd_oxfw_stream_parse_format(formats[i], &formation);
129 if (err < 0)
130 goto end;
131 if (rate != formation.rate)
132 continue;
133 if (pcm_channels == 0 || pcm_channels == formation.pcm)
134 break;
135 }
136 if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
137 err = -EINVAL;
74 goto end; 138 goto end;
139 }
75 140
76 err = cmp_connection_establish(&oxfw->in_conn, 141 pcm_channels = formation.pcm;
77 amdtp_stream_get_max_payload(&oxfw->rx_stream)); 142 midi_ports = DIV_ROUND_UP(formation.midi, 8);
143
144 /* The stream should have one pcm channels at least */
145 if (pcm_channels == 0) {
146 err = -EINVAL;
147 goto end;
148 }
149 amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
150
151 err = cmp_connection_establish(conn,
152 amdtp_stream_get_max_payload(stream));
78 if (err < 0) 153 if (err < 0)
79 goto end; 154 goto end;
80 155
81 err = amdtp_stream_start(&oxfw->rx_stream, 156 err = amdtp_stream_start(stream,
82 oxfw->in_conn.resources.channel, 157 conn->resources.channel,
83 oxfw->in_conn.speed); 158 conn->speed);
159 if (err < 0) {
160 cmp_connection_break(conn);
161 goto end;
162 }
163
164 /* Wait first packet */
165 err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
84 if (err < 0) 166 if (err < 0)
85 stop_stream(oxfw); 167 stop_stream(oxfw);
86end: 168end:
87 return err; 169 return err;
88} 170}
89 171
172int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate,
173 unsigned int pcm_channels)
174{
175 struct snd_oxfw_stream_formation formation;
176 int err = 0;
177
178 /* packet queueing error */
179 if (amdtp_streaming_error(&oxfw->rx_stream))
180 stop_stream(oxfw);
181
182 err = snd_oxfw_stream_get_current_formation(oxfw,
183 AVC_GENERAL_PLUG_DIR_IN,
184 &formation);
185 if (err < 0)
186 goto end;
187
188 if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
189 stop_stream(oxfw);
190
191 /* arrange sampling rate */
192 err = set_stream_format(oxfw, &oxfw->rx_stream, rate,
193 pcm_channels);
194 if (err < 0) {
195 dev_err(&oxfw->unit->device,
196 "fail to set stream format: %d\n", err);
197 goto end;
198 }
199 }
200
201 err = start_stream(oxfw, rate, pcm_channels);
202 if (err < 0)
203 dev_err(&oxfw->unit->device,
204 "fail to start stream: %d\n", err);
205end:
206 return err;
207}
208
90void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw) 209void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw)
91{ 210{
92 stop_stream(oxfw); 211 stop_stream(oxfw);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
index 8c832ea6aae0..c09ef38c22ba 100644
--- a/sound/firewire/oxfw/oxfw.h
+++ b/sound/firewire/oxfw/oxfw.h
@@ -89,7 +89,8 @@ int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
89 unsigned short pid); 89 unsigned short pid);
90 90
91int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw); 91int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw);
92int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw); 92int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw, unsigned int rate,
93 unsigned int pcm_channels);
93void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw); 94void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw);
94void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw); 95void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw);
95void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw); 96void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw);