0001
0002
0003
0004
0005
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
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
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
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
0155
0156
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 }