Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * ff-stream.c - a part of driver for RME Fireface series
0004  *
0005  * Copyright (c) 2015-2017 Takashi Sakamoto
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  * This function should be called before starting streams or after stopping
0099  * streams.
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      * Regardless of current source of clock signal, drivers transfer some
0183      * packets. Then, the device transfers packets.
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         // NOTE: The device doesn't transfer packets unless receiving any packet. The
0203         // sequence of tx packets includes cycle skip corresponding to empty packet or
0204         // NODATA packet in IEC 61883-1/6. The sequence of the number of data blocks per
0205         // packet is important for media clock recovery.
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     // The device discontinue to transfer packets.
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     /* user land lock this */
0261     if (ff->dev_lock_count < 0) {
0262         err = -EBUSY;
0263         goto end;
0264     }
0265 
0266     /* this is the first time */
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 }