0001
0002
0003
0004
0005
0006
0007
0008 #include "ff.h"
0009
0010 #define READY_TIMEOUT_MS 200
0011
0012 int snd_ff_stream_get_multiplier_mode(enum cip_sfc sfc,
0013 enum snd_ff_stream_mode *mode)
0014 {
0015 static const enum snd_ff_stream_mode modes[] = {
0016 [CIP_SFC_32000] = SND_FF_STREAM_MODE_LOW,
0017 [CIP_SFC_44100] = SND_FF_STREAM_MODE_LOW,
0018 [CIP_SFC_48000] = SND_FF_STREAM_MODE_LOW,
0019 [CIP_SFC_88200] = SND_FF_STREAM_MODE_MID,
0020 [CIP_SFC_96000] = SND_FF_STREAM_MODE_MID,
0021 [CIP_SFC_176400] = SND_FF_STREAM_MODE_HIGH,
0022 [CIP_SFC_192000] = SND_FF_STREAM_MODE_HIGH,
0023 };
0024
0025 if (sfc >= CIP_SFC_COUNT)
0026 return -EINVAL;
0027
0028 *mode = modes[sfc];
0029
0030 return 0;
0031 }
0032
0033 static inline void finish_session(struct snd_ff *ff)
0034 {
0035 ff->spec->protocol->finish_session(ff);
0036 ff->spec->protocol->switch_fetching_mode(ff, false);
0037 }
0038
0039 static int init_stream(struct snd_ff *ff, struct amdtp_stream *s)
0040 {
0041 struct fw_iso_resources *resources;
0042 enum amdtp_stream_direction dir;
0043 int err;
0044
0045 if (s == &ff->tx_stream) {
0046 resources = &ff->tx_resources;
0047 dir = AMDTP_IN_STREAM;
0048 } else {
0049 resources = &ff->rx_resources;
0050 dir = AMDTP_OUT_STREAM;
0051 }
0052
0053 err = fw_iso_resources_init(resources, ff->unit);
0054 if (err < 0)
0055 return err;
0056
0057 err = amdtp_ff_init(s, ff->unit, dir);
0058 if (err < 0)
0059 fw_iso_resources_destroy(resources);
0060
0061 return err;
0062 }
0063
0064 static void destroy_stream(struct snd_ff *ff, struct amdtp_stream *s)
0065 {
0066 amdtp_stream_destroy(s);
0067
0068 if (s == &ff->tx_stream)
0069 fw_iso_resources_destroy(&ff->tx_resources);
0070 else
0071 fw_iso_resources_destroy(&ff->rx_resources);
0072 }
0073
0074 int snd_ff_stream_init_duplex(struct snd_ff *ff)
0075 {
0076 int err;
0077
0078 err = init_stream(ff, &ff->rx_stream);
0079 if (err < 0)
0080 return err;
0081
0082 err = init_stream(ff, &ff->tx_stream);
0083 if (err < 0) {
0084 destroy_stream(ff, &ff->rx_stream);
0085 return err;
0086 }
0087
0088 err = amdtp_domain_init(&ff->domain);
0089 if (err < 0) {
0090 destroy_stream(ff, &ff->rx_stream);
0091 destroy_stream(ff, &ff->tx_stream);
0092 }
0093
0094 return err;
0095 }
0096
0097
0098
0099
0100
0101 void snd_ff_stream_destroy_duplex(struct snd_ff *ff)
0102 {
0103 amdtp_domain_destroy(&ff->domain);
0104
0105 destroy_stream(ff, &ff->rx_stream);
0106 destroy_stream(ff, &ff->tx_stream);
0107 }
0108
0109 int snd_ff_stream_reserve_duplex(struct snd_ff *ff, unsigned int rate,
0110 unsigned int frames_per_period,
0111 unsigned int frames_per_buffer)
0112 {
0113 unsigned int curr_rate;
0114 enum snd_ff_clock_src src;
0115 int err;
0116
0117 err = ff->spec->protocol->get_clock(ff, &curr_rate, &src);
0118 if (err < 0)
0119 return err;
0120
0121 if (ff->substreams_counter == 0 || curr_rate != rate) {
0122 enum snd_ff_stream_mode mode;
0123 int i;
0124
0125 amdtp_domain_stop(&ff->domain);
0126 finish_session(ff);
0127
0128 fw_iso_resources_free(&ff->tx_resources);
0129 fw_iso_resources_free(&ff->rx_resources);
0130
0131 for (i = 0; i < CIP_SFC_COUNT; ++i) {
0132 if (amdtp_rate_table[i] == rate)
0133 break;
0134 }
0135 if (i >= CIP_SFC_COUNT)
0136 return -EINVAL;
0137
0138 err = snd_ff_stream_get_multiplier_mode(i, &mode);
0139 if (err < 0)
0140 return err;
0141
0142 err = amdtp_ff_set_parameters(&ff->tx_stream, rate,
0143 ff->spec->pcm_capture_channels[mode]);
0144 if (err < 0)
0145 return err;
0146
0147 err = amdtp_ff_set_parameters(&ff->rx_stream, rate,
0148 ff->spec->pcm_playback_channels[mode]);
0149 if (err < 0)
0150 return err;
0151
0152 err = ff->spec->protocol->allocate_resources(ff, rate);
0153 if (err < 0)
0154 return err;
0155
0156 err = amdtp_domain_set_events_per_period(&ff->domain,
0157 frames_per_period, frames_per_buffer);
0158 if (err < 0) {
0159 fw_iso_resources_free(&ff->tx_resources);
0160 fw_iso_resources_free(&ff->rx_resources);
0161 return err;
0162 }
0163 }
0164
0165 return 0;
0166 }
0167
0168 int snd_ff_stream_start_duplex(struct snd_ff *ff, unsigned int rate)
0169 {
0170 int err;
0171
0172 if (ff->substreams_counter == 0)
0173 return 0;
0174
0175 if (amdtp_streaming_error(&ff->tx_stream) ||
0176 amdtp_streaming_error(&ff->rx_stream)) {
0177 amdtp_domain_stop(&ff->domain);
0178 finish_session(ff);
0179 }
0180
0181
0182
0183
0184
0185 if (!amdtp_stream_running(&ff->rx_stream)) {
0186 int spd = fw_parent_device(ff->unit)->max_speed;
0187
0188 err = ff->spec->protocol->begin_session(ff, rate);
0189 if (err < 0)
0190 goto error;
0191
0192 err = amdtp_domain_add_stream(&ff->domain, &ff->rx_stream,
0193 ff->rx_resources.channel, spd);
0194 if (err < 0)
0195 goto error;
0196
0197 err = amdtp_domain_add_stream(&ff->domain, &ff->tx_stream,
0198 ff->tx_resources.channel, spd);
0199 if (err < 0)
0200 goto error;
0201
0202
0203
0204
0205
0206 err = amdtp_domain_start(&ff->domain, 0, true, true);
0207 if (err < 0)
0208 goto error;
0209
0210 if (!amdtp_domain_wait_ready(&ff->domain, READY_TIMEOUT_MS)) {
0211 err = -ETIMEDOUT;
0212 goto error;
0213 }
0214
0215 err = ff->spec->protocol->switch_fetching_mode(ff, true);
0216 if (err < 0)
0217 goto error;
0218 }
0219
0220 return 0;
0221 error:
0222 amdtp_domain_stop(&ff->domain);
0223 finish_session(ff);
0224
0225 return err;
0226 }
0227
0228 void snd_ff_stream_stop_duplex(struct snd_ff *ff)
0229 {
0230 if (ff->substreams_counter == 0) {
0231 amdtp_domain_stop(&ff->domain);
0232 finish_session(ff);
0233
0234 fw_iso_resources_free(&ff->tx_resources);
0235 fw_iso_resources_free(&ff->rx_resources);
0236 }
0237 }
0238
0239 void snd_ff_stream_update_duplex(struct snd_ff *ff)
0240 {
0241 amdtp_domain_stop(&ff->domain);
0242
0243
0244 amdtp_stream_pcm_abort(&ff->tx_stream);
0245 amdtp_stream_pcm_abort(&ff->rx_stream);
0246 }
0247
0248 void snd_ff_stream_lock_changed(struct snd_ff *ff)
0249 {
0250 ff->dev_lock_changed = true;
0251 wake_up(&ff->hwdep_wait);
0252 }
0253
0254 int snd_ff_stream_lock_try(struct snd_ff *ff)
0255 {
0256 int err;
0257
0258 spin_lock_irq(&ff->lock);
0259
0260
0261 if (ff->dev_lock_count < 0) {
0262 err = -EBUSY;
0263 goto end;
0264 }
0265
0266
0267 if (ff->dev_lock_count++ == 0)
0268 snd_ff_stream_lock_changed(ff);
0269 err = 0;
0270 end:
0271 spin_unlock_irq(&ff->lock);
0272 return err;
0273 }
0274
0275 void snd_ff_stream_lock_release(struct snd_ff *ff)
0276 {
0277 spin_lock_irq(&ff->lock);
0278
0279 if (WARN_ON(ff->dev_lock_count <= 0))
0280 goto end;
0281 if (--ff->dev_lock_count == 0)
0282 snd_ff_stream_lock_changed(ff);
0283 end:
0284 spin_unlock_irq(&ff->lock);
0285 }