0001
0002
0003
0004
0005
0006
0007
0008 #include "oxfw.h"
0009
0010 static int hw_rule_rate(struct snd_pcm_hw_params *params,
0011 struct snd_pcm_hw_rule *rule)
0012 {
0013 u8 **formats = 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 struct snd_oxfw_stream_formation formation;
0022 int i, err;
0023
0024 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
0025 if (formats[i] == NULL)
0026 continue;
0027
0028 err = snd_oxfw_stream_parse_format(formats[i], &formation);
0029 if (err < 0)
0030 continue;
0031 if (!snd_interval_test(c, formation.pcm))
0032 continue;
0033
0034 t.min = min(t.min, formation.rate);
0035 t.max = max(t.max, formation.rate);
0036
0037 }
0038 return snd_interval_refine(r, &t);
0039 }
0040
0041 static int hw_rule_channels(struct snd_pcm_hw_params *params,
0042 struct snd_pcm_hw_rule *rule)
0043 {
0044 u8 **formats = rule->private;
0045 struct snd_interval *c =
0046 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
0047 const struct snd_interval *r =
0048 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
0049 struct snd_oxfw_stream_formation formation;
0050 int i, j, err;
0051 unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0};
0052
0053 count = 0;
0054 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
0055 if (formats[i] == NULL)
0056 break;
0057
0058 err = snd_oxfw_stream_parse_format(formats[i], &formation);
0059 if (err < 0)
0060 continue;
0061 if (!snd_interval_test(r, formation.rate))
0062 continue;
0063 if (list[count] == formation.pcm)
0064 continue;
0065
0066 for (j = 0; j < ARRAY_SIZE(list); j++) {
0067 if (list[j] == formation.pcm)
0068 break;
0069 }
0070 if (j == ARRAY_SIZE(list)) {
0071 list[count] = formation.pcm;
0072 if (++count == ARRAY_SIZE(list))
0073 break;
0074 }
0075 }
0076
0077 return snd_interval_list(c, count, list, 0);
0078 }
0079
0080 static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats)
0081 {
0082 struct snd_oxfw_stream_formation formation;
0083 int i, err;
0084
0085 hw->channels_min = UINT_MAX;
0086 hw->channels_max = 0;
0087
0088 hw->rate_min = UINT_MAX;
0089 hw->rate_max = 0;
0090 hw->rates = 0;
0091
0092 for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
0093 if (formats[i] == NULL)
0094 break;
0095
0096 err = snd_oxfw_stream_parse_format(formats[i], &formation);
0097 if (err < 0)
0098 continue;
0099
0100 hw->channels_min = min(hw->channels_min, formation.pcm);
0101 hw->channels_max = max(hw->channels_max, formation.pcm);
0102
0103 hw->rate_min = min(hw->rate_min, formation.rate);
0104 hw->rate_max = max(hw->rate_max, formation.rate);
0105 hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate);
0106 }
0107 }
0108
0109 static int init_hw_params(struct snd_oxfw *oxfw,
0110 struct snd_pcm_substream *substream)
0111 {
0112 struct snd_pcm_runtime *runtime = substream->runtime;
0113 u8 **formats;
0114 struct amdtp_stream *stream;
0115 int err;
0116
0117 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
0118 runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
0119 stream = &oxfw->tx_stream;
0120 formats = oxfw->tx_stream_formats;
0121 } else {
0122 runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
0123 stream = &oxfw->rx_stream;
0124 formats = oxfw->rx_stream_formats;
0125 }
0126
0127 limit_channels_and_rates(&runtime->hw, formats);
0128
0129 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
0130 hw_rule_channels, formats,
0131 SNDRV_PCM_HW_PARAM_RATE, -1);
0132 if (err < 0)
0133 goto end;
0134
0135 err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
0136 hw_rule_rate, formats,
0137 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
0138 if (err < 0)
0139 goto end;
0140
0141 err = amdtp_am824_add_pcm_hw_constraints(stream, runtime);
0142 end:
0143 return err;
0144 }
0145
0146 static int limit_to_current_params(struct snd_pcm_substream *substream)
0147 {
0148 struct snd_oxfw *oxfw = substream->private_data;
0149 struct snd_oxfw_stream_formation formation;
0150 enum avc_general_plug_dir dir;
0151 int err;
0152
0153 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
0154 dir = AVC_GENERAL_PLUG_DIR_OUT;
0155 else
0156 dir = AVC_GENERAL_PLUG_DIR_IN;
0157
0158 err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
0159 if (err < 0)
0160 goto end;
0161
0162 substream->runtime->hw.channels_min = formation.pcm;
0163 substream->runtime->hw.channels_max = formation.pcm;
0164 substream->runtime->hw.rate_min = formation.rate;
0165 substream->runtime->hw.rate_max = formation.rate;
0166 end:
0167 return err;
0168 }
0169
0170 static int pcm_open(struct snd_pcm_substream *substream)
0171 {
0172 struct snd_oxfw *oxfw = substream->private_data;
0173 struct amdtp_domain *d = &oxfw->domain;
0174 int err;
0175
0176 err = snd_oxfw_stream_lock_try(oxfw);
0177 if (err < 0)
0178 return err;
0179
0180 err = init_hw_params(oxfw, substream);
0181 if (err < 0)
0182 goto err_locked;
0183
0184 mutex_lock(&oxfw->mutex);
0185
0186
0187
0188
0189 if (oxfw->substreams_count > 0 && d->events_per_period > 0) {
0190 unsigned int frames_per_period = d->events_per_period;
0191 unsigned int frames_per_buffer = d->events_per_buffer;
0192
0193 err = limit_to_current_params(substream);
0194 if (err < 0) {
0195 mutex_unlock(&oxfw->mutex);
0196 goto err_locked;
0197 }
0198
0199 if (frames_per_period > 0) {
0200 err = snd_pcm_hw_constraint_minmax(substream->runtime,
0201 SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
0202 frames_per_period, frames_per_period);
0203 if (err < 0) {
0204 mutex_unlock(&oxfw->mutex);
0205 goto err_locked;
0206 }
0207
0208 err = snd_pcm_hw_constraint_minmax(substream->runtime,
0209 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
0210 frames_per_buffer, frames_per_buffer);
0211 if (err < 0) {
0212 mutex_unlock(&oxfw->mutex);
0213 goto err_locked;
0214 }
0215 }
0216 }
0217
0218 mutex_unlock(&oxfw->mutex);
0219
0220 snd_pcm_set_sync(substream);
0221
0222 return 0;
0223 err_locked:
0224 snd_oxfw_stream_lock_release(oxfw);
0225 return err;
0226 }
0227
0228 static int pcm_close(struct snd_pcm_substream *substream)
0229 {
0230 struct snd_oxfw *oxfw = substream->private_data;
0231
0232 snd_oxfw_stream_lock_release(oxfw);
0233 return 0;
0234 }
0235
0236 static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
0237 struct snd_pcm_hw_params *hw_params)
0238 {
0239 struct snd_oxfw *oxfw = substream->private_data;
0240 int err = 0;
0241
0242 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
0243 unsigned int rate = params_rate(hw_params);
0244 unsigned int channels = params_channels(hw_params);
0245 unsigned int frames_per_period = params_period_size(hw_params);
0246 unsigned int frames_per_buffer = params_buffer_size(hw_params);
0247
0248 mutex_lock(&oxfw->mutex);
0249 err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->tx_stream,
0250 rate, channels, frames_per_period,
0251 frames_per_buffer);
0252 if (err >= 0)
0253 ++oxfw->substreams_count;
0254 mutex_unlock(&oxfw->mutex);
0255 }
0256
0257 return err;
0258 }
0259 static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
0260 struct snd_pcm_hw_params *hw_params)
0261 {
0262 struct snd_oxfw *oxfw = substream->private_data;
0263 int err = 0;
0264
0265 if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
0266 unsigned int rate = params_rate(hw_params);
0267 unsigned int channels = params_channels(hw_params);
0268 unsigned int frames_per_period = params_period_size(hw_params);
0269 unsigned int frames_per_buffer = params_buffer_size(hw_params);
0270
0271 mutex_lock(&oxfw->mutex);
0272 err = snd_oxfw_stream_reserve_duplex(oxfw, &oxfw->rx_stream,
0273 rate, channels, frames_per_period,
0274 frames_per_buffer);
0275 if (err >= 0)
0276 ++oxfw->substreams_count;
0277 mutex_unlock(&oxfw->mutex);
0278 }
0279
0280 return err;
0281 }
0282
0283 static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
0284 {
0285 struct snd_oxfw *oxfw = substream->private_data;
0286
0287 mutex_lock(&oxfw->mutex);
0288
0289 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
0290 --oxfw->substreams_count;
0291
0292 snd_oxfw_stream_stop_duplex(oxfw);
0293
0294 mutex_unlock(&oxfw->mutex);
0295
0296 return 0;
0297 }
0298 static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
0299 {
0300 struct snd_oxfw *oxfw = substream->private_data;
0301
0302 mutex_lock(&oxfw->mutex);
0303
0304 if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
0305 --oxfw->substreams_count;
0306
0307 snd_oxfw_stream_stop_duplex(oxfw);
0308
0309 mutex_unlock(&oxfw->mutex);
0310
0311 return 0;
0312 }
0313
0314 static int pcm_capture_prepare(struct snd_pcm_substream *substream)
0315 {
0316 struct snd_oxfw *oxfw = substream->private_data;
0317 int err;
0318
0319 mutex_lock(&oxfw->mutex);
0320 err = snd_oxfw_stream_start_duplex(oxfw);
0321 mutex_unlock(&oxfw->mutex);
0322 if (err < 0)
0323 goto end;
0324
0325 amdtp_stream_pcm_prepare(&oxfw->tx_stream);
0326 end:
0327 return err;
0328 }
0329 static int pcm_playback_prepare(struct snd_pcm_substream *substream)
0330 {
0331 struct snd_oxfw *oxfw = substream->private_data;
0332 int err;
0333
0334 mutex_lock(&oxfw->mutex);
0335 err = snd_oxfw_stream_start_duplex(oxfw);
0336 mutex_unlock(&oxfw->mutex);
0337 if (err < 0)
0338 goto end;
0339
0340 amdtp_stream_pcm_prepare(&oxfw->rx_stream);
0341 end:
0342 return err;
0343 }
0344
0345 static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
0346 {
0347 struct snd_oxfw *oxfw = substream->private_data;
0348 struct snd_pcm_substream *pcm;
0349
0350 switch (cmd) {
0351 case SNDRV_PCM_TRIGGER_START:
0352 pcm = substream;
0353 break;
0354 case SNDRV_PCM_TRIGGER_STOP:
0355 pcm = NULL;
0356 break;
0357 default:
0358 return -EINVAL;
0359 }
0360 amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm);
0361 return 0;
0362 }
0363 static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
0364 {
0365 struct snd_oxfw *oxfw = substream->private_data;
0366 struct snd_pcm_substream *pcm;
0367
0368 switch (cmd) {
0369 case SNDRV_PCM_TRIGGER_START:
0370 pcm = substream;
0371 break;
0372 case SNDRV_PCM_TRIGGER_STOP:
0373 pcm = NULL;
0374 break;
0375 default:
0376 return -EINVAL;
0377 }
0378 amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
0379 return 0;
0380 }
0381
0382 static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
0383 {
0384 struct snd_oxfw *oxfw = sbstm->private_data;
0385
0386 return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->tx_stream);
0387 }
0388 static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
0389 {
0390 struct snd_oxfw *oxfw = sbstm->private_data;
0391
0392 return amdtp_domain_stream_pcm_pointer(&oxfw->domain, &oxfw->rx_stream);
0393 }
0394
0395 static int pcm_capture_ack(struct snd_pcm_substream *substream)
0396 {
0397 struct snd_oxfw *oxfw = substream->private_data;
0398
0399 return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->tx_stream);
0400 }
0401
0402 static int pcm_playback_ack(struct snd_pcm_substream *substream)
0403 {
0404 struct snd_oxfw *oxfw = substream->private_data;
0405
0406 return amdtp_domain_stream_pcm_ack(&oxfw->domain, &oxfw->rx_stream);
0407 }
0408
0409 int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
0410 {
0411 static const struct snd_pcm_ops capture_ops = {
0412 .open = pcm_open,
0413 .close = pcm_close,
0414 .hw_params = pcm_capture_hw_params,
0415 .hw_free = pcm_capture_hw_free,
0416 .prepare = pcm_capture_prepare,
0417 .trigger = pcm_capture_trigger,
0418 .pointer = pcm_capture_pointer,
0419 .ack = pcm_capture_ack,
0420 };
0421 static const struct snd_pcm_ops playback_ops = {
0422 .open = pcm_open,
0423 .close = pcm_close,
0424 .hw_params = pcm_playback_hw_params,
0425 .hw_free = pcm_playback_hw_free,
0426 .prepare = pcm_playback_prepare,
0427 .trigger = pcm_playback_trigger,
0428 .pointer = pcm_playback_pointer,
0429 .ack = pcm_playback_ack,
0430 };
0431 struct snd_pcm *pcm;
0432 unsigned int cap = 0;
0433 int err;
0434
0435 if (oxfw->has_output)
0436 cap = 1;
0437
0438 err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm);
0439 if (err < 0)
0440 return err;
0441
0442 pcm->private_data = oxfw;
0443 strcpy(pcm->name, oxfw->card->shortname);
0444 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
0445 if (cap > 0)
0446 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
0447 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
0448
0449 return 0;
0450 }