Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * digi00x-pcm.c - a part of driver for Digidesign Digi 002/003 family
0004  *
0005  * Copyright (c) 2014-2015 Takashi Sakamoto
0006  */
0007 
0008 #include "digi00x.h"
0009 
0010 static int hw_rule_rate(struct snd_pcm_hw_params *params,
0011             struct snd_pcm_hw_rule *rule)
0012 {
0013     struct snd_interval *r =
0014         hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
0015     const struct snd_interval *c =
0016         hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0017     struct snd_interval t = {
0018         .min = UINT_MAX, .max = 0, .integer = 1,
0019     };
0020     unsigned int i;
0021 
0022     for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
0023         if (!snd_interval_test(c,
0024                        snd_dg00x_stream_pcm_channels[i]))
0025             continue;
0026 
0027         t.min = min(t.min, snd_dg00x_stream_rates[i]);
0028         t.max = max(t.max, snd_dg00x_stream_rates[i]);
0029     }
0030 
0031     return snd_interval_refine(r, &t);
0032 }
0033 
0034 static int hw_rule_channels(struct snd_pcm_hw_params *params,
0035                 struct snd_pcm_hw_rule *rule)
0036 {
0037     struct snd_interval *c =
0038         hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0039     const struct snd_interval *r =
0040         hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
0041     struct snd_interval t = {
0042         .min = UINT_MAX, .max = 0, .integer = 1,
0043     };
0044     unsigned int i;
0045 
0046     for (i = 0; i < SND_DG00X_RATE_COUNT; i++) {
0047         if (!snd_interval_test(r, snd_dg00x_stream_rates[i]))
0048             continue;
0049 
0050         t.min = min(t.min, snd_dg00x_stream_pcm_channels[i]);
0051         t.max = max(t.max, snd_dg00x_stream_pcm_channels[i]);
0052     }
0053 
0054     return snd_interval_refine(c, &t);
0055 }
0056 
0057 static int pcm_init_hw_params(struct snd_dg00x *dg00x,
0058                   struct snd_pcm_substream *substream)
0059 {
0060     struct snd_pcm_runtime *runtime = substream->runtime;
0061     struct snd_pcm_hardware *hw = &runtime->hw;
0062     struct amdtp_stream *s;
0063     int err;
0064 
0065 
0066     if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0067         substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
0068         s = &dg00x->tx_stream;
0069     } else {
0070         substream->runtime->hw.formats = SNDRV_PCM_FMTBIT_S32;
0071         s = &dg00x->rx_stream;
0072     }
0073 
0074     hw->channels_min = 10;
0075     hw->channels_max = 18;
0076 
0077     hw->rates = SNDRV_PCM_RATE_44100 |
0078             SNDRV_PCM_RATE_48000 |
0079             SNDRV_PCM_RATE_88200 |
0080             SNDRV_PCM_RATE_96000;
0081     snd_pcm_limit_hw_rates(runtime);
0082 
0083     err = snd_pcm_hw_rule_add(substream->runtime, 0,
0084                   SNDRV_PCM_HW_PARAM_CHANNELS,
0085                   hw_rule_channels, NULL,
0086                   SNDRV_PCM_HW_PARAM_RATE, -1);
0087     if (err < 0)
0088         return err;
0089 
0090     err = snd_pcm_hw_rule_add(substream->runtime, 0,
0091                   SNDRV_PCM_HW_PARAM_RATE,
0092                   hw_rule_rate, NULL,
0093                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
0094     if (err < 0)
0095         return err;
0096 
0097     return amdtp_dot_add_pcm_hw_constraints(s, substream->runtime);
0098 }
0099 
0100 static int pcm_open(struct snd_pcm_substream *substream)
0101 {
0102     struct snd_dg00x *dg00x = substream->private_data;
0103     struct amdtp_domain *d = &dg00x->domain;
0104     enum snd_dg00x_clock clock;
0105     bool detect;
0106     int err;
0107 
0108     err = snd_dg00x_stream_lock_try(dg00x);
0109     if (err < 0)
0110         return err;
0111 
0112     err = pcm_init_hw_params(dg00x, substream);
0113     if (err < 0)
0114         goto err_locked;
0115 
0116     /* Check current clock source. */
0117     err = snd_dg00x_stream_get_clock(dg00x, &clock);
0118     if (err < 0)
0119         goto err_locked;
0120     if (clock != SND_DG00X_CLOCK_INTERNAL) {
0121         err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
0122         if (err < 0)
0123             goto err_locked;
0124         if (!detect) {
0125             err = -EBUSY;
0126             goto err_locked;
0127         }
0128     }
0129 
0130     mutex_lock(&dg00x->mutex);
0131 
0132     // When source of clock is not internal or any stream is reserved for
0133     // transmission of PCM frames, the available sampling rate is limited
0134     // at current one.
0135     if ((clock != SND_DG00X_CLOCK_INTERNAL) ||
0136         (dg00x->substreams_counter > 0 && d->events_per_period > 0)) {
0137         unsigned int frames_per_period = d->events_per_period;
0138         unsigned int frames_per_buffer = d->events_per_buffer;
0139         unsigned int rate;
0140 
0141         err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
0142         if (err < 0) {
0143             mutex_unlock(&dg00x->mutex);
0144             goto err_locked;
0145         }
0146         substream->runtime->hw.rate_min = rate;
0147         substream->runtime->hw.rate_max = rate;
0148 
0149         if (frames_per_period > 0) {
0150             err = snd_pcm_hw_constraint_minmax(substream->runtime,
0151                     SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
0152                     frames_per_period, frames_per_period);
0153             if (err < 0) {
0154                 mutex_unlock(&dg00x->mutex);
0155                 goto err_locked;
0156             }
0157 
0158             err = snd_pcm_hw_constraint_minmax(substream->runtime,
0159                     SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
0160                     frames_per_buffer, frames_per_buffer);
0161             if (err < 0) {
0162                 mutex_unlock(&dg00x->mutex);
0163                 goto err_locked;
0164             }
0165         }
0166     }
0167 
0168     mutex_unlock(&dg00x->mutex);
0169 
0170     snd_pcm_set_sync(substream);
0171 
0172     return 0;
0173 err_locked:
0174     snd_dg00x_stream_lock_release(dg00x);
0175     return err;
0176 }
0177 
0178 static int pcm_close(struct snd_pcm_substream *substream)
0179 {
0180     struct snd_dg00x *dg00x = substream->private_data;
0181 
0182     snd_dg00x_stream_lock_release(dg00x);
0183 
0184     return 0;
0185 }
0186 
0187 static int pcm_hw_params(struct snd_pcm_substream *substream,
0188              struct snd_pcm_hw_params *hw_params)
0189 {
0190     struct snd_dg00x *dg00x = substream->private_data;
0191     int err = 0;
0192 
0193     if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
0194         unsigned int rate = params_rate(hw_params);
0195         unsigned int frames_per_period = params_period_size(hw_params);
0196         unsigned int frames_per_buffer = params_buffer_size(hw_params);
0197 
0198         mutex_lock(&dg00x->mutex);
0199         err = snd_dg00x_stream_reserve_duplex(dg00x, rate,
0200                     frames_per_period, frames_per_buffer);
0201         if (err >= 0)
0202             ++dg00x->substreams_counter;
0203         mutex_unlock(&dg00x->mutex);
0204     }
0205 
0206     return err;
0207 }
0208 
0209 static int pcm_hw_free(struct snd_pcm_substream *substream)
0210 {
0211     struct snd_dg00x *dg00x = substream->private_data;
0212 
0213     mutex_lock(&dg00x->mutex);
0214 
0215     if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
0216         --dg00x->substreams_counter;
0217 
0218     snd_dg00x_stream_stop_duplex(dg00x);
0219 
0220     mutex_unlock(&dg00x->mutex);
0221 
0222     return 0;
0223 }
0224 
0225 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
0226 {
0227     struct snd_dg00x *dg00x = substream->private_data;
0228     int err;
0229 
0230     mutex_lock(&dg00x->mutex);
0231 
0232     err = snd_dg00x_stream_start_duplex(dg00x);
0233     if (err >= 0)
0234         amdtp_stream_pcm_prepare(&dg00x->tx_stream);
0235 
0236     mutex_unlock(&dg00x->mutex);
0237 
0238     return err;
0239 }
0240 
0241 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
0242 {
0243     struct snd_dg00x *dg00x = substream->private_data;
0244     int err;
0245 
0246     mutex_lock(&dg00x->mutex);
0247 
0248     err = snd_dg00x_stream_start_duplex(dg00x);
0249     if (err >= 0) {
0250         amdtp_stream_pcm_prepare(&dg00x->rx_stream);
0251         amdtp_dot_reset(&dg00x->rx_stream);
0252     }
0253 
0254     mutex_unlock(&dg00x->mutex);
0255 
0256     return err;
0257 }
0258 
0259 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
0260 {
0261     struct snd_dg00x *dg00x = substream->private_data;
0262 
0263     switch (cmd) {
0264     case SNDRV_PCM_TRIGGER_START:
0265         amdtp_stream_pcm_trigger(&dg00x->tx_stream, substream);
0266         break;
0267     case SNDRV_PCM_TRIGGER_STOP:
0268         amdtp_stream_pcm_trigger(&dg00x->tx_stream, NULL);
0269         break;
0270     default:
0271         return -EINVAL;
0272     }
0273 
0274     return 0;
0275 }
0276 
0277 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
0278 {
0279     struct snd_dg00x *dg00x = substream->private_data;
0280 
0281     switch (cmd) {
0282     case SNDRV_PCM_TRIGGER_START:
0283         amdtp_stream_pcm_trigger(&dg00x->rx_stream, substream);
0284         break;
0285     case SNDRV_PCM_TRIGGER_STOP:
0286         amdtp_stream_pcm_trigger(&dg00x->rx_stream, NULL);
0287         break;
0288     default:
0289         return -EINVAL;
0290     }
0291 
0292     return 0;
0293 }
0294 
0295 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
0296 {
0297     struct snd_dg00x *dg00x = sbstrm->private_data;
0298 
0299     return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->tx_stream);
0300 }
0301 
0302 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
0303 {
0304     struct snd_dg00x *dg00x = sbstrm->private_data;
0305 
0306     return amdtp_domain_stream_pcm_pointer(&dg00x->domain, &dg00x->rx_stream);
0307 }
0308 
0309 static int pcm_capture_ack(struct snd_pcm_substream *substream)
0310 {
0311     struct snd_dg00x *dg00x = substream->private_data;
0312 
0313     return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->tx_stream);
0314 }
0315 
0316 static int pcm_playback_ack(struct snd_pcm_substream *substream)
0317 {
0318     struct snd_dg00x *dg00x = substream->private_data;
0319 
0320     return amdtp_domain_stream_pcm_ack(&dg00x->domain, &dg00x->rx_stream);
0321 }
0322 
0323 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
0324 {
0325     static const struct snd_pcm_ops capture_ops = {
0326         .open       = pcm_open,
0327         .close      = pcm_close,
0328         .hw_params  = pcm_hw_params,
0329         .hw_free    = pcm_hw_free,
0330         .prepare    = pcm_capture_prepare,
0331         .trigger    = pcm_capture_trigger,
0332         .pointer    = pcm_capture_pointer,
0333         .ack        = pcm_capture_ack,
0334     };
0335     static const struct snd_pcm_ops playback_ops = {
0336         .open       = pcm_open,
0337         .close      = pcm_close,
0338         .hw_params  = pcm_hw_params,
0339         .hw_free    = pcm_hw_free,
0340         .prepare    = pcm_playback_prepare,
0341         .trigger    = pcm_playback_trigger,
0342         .pointer    = pcm_playback_pointer,
0343         .ack        = pcm_playback_ack,
0344     };
0345     struct snd_pcm *pcm;
0346     int err;
0347 
0348     err = snd_pcm_new(dg00x->card, dg00x->card->driver, 0, 1, 1, &pcm);
0349     if (err < 0)
0350         return err;
0351 
0352     pcm->private_data = dg00x;
0353     snprintf(pcm->name, sizeof(pcm->name),
0354          "%s PCM", dg00x->card->shortname);
0355     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
0356     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
0357     snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
0358 
0359     return 0;
0360 }