Back to home page

OSCL-LXR

 
 

    


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