root/sound/firewire/bebob/bebob_pcm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hw_rule_rate
  2. hw_rule_channels
  3. limit_channels_and_rates
  4. pcm_init_hw_params
  5. pcm_open
  6. pcm_close
  7. pcm_hw_params
  8. pcm_hw_free
  9. pcm_capture_prepare
  10. pcm_playback_prepare
  11. pcm_capture_trigger
  12. pcm_playback_trigger
  13. pcm_capture_pointer
  14. pcm_playback_pointer
  15. pcm_capture_ack
  16. pcm_playback_ack
  17. snd_bebob_create_pcm_devices

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * bebob_pcm.c - a part of driver for BeBoB based devices
   4  *
   5  * Copyright (c) 2013-2014 Takashi Sakamoto
   6  */
   7 
   8 #include "./bebob.h"
   9 
  10 static int
  11 hw_rule_rate(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
  12 {
  13         struct snd_bebob_stream_formation *formations = rule->private;
  14         struct snd_interval *r =
  15                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
  16         const struct snd_interval *c =
  17                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  18         struct snd_interval t = {
  19                 .min = UINT_MAX, .max = 0, .integer = 1
  20         };
  21         unsigned int i;
  22 
  23         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  24                 /* entry is invalid */
  25                 if (formations[i].pcm == 0)
  26                         continue;
  27 
  28                 if (!snd_interval_test(c, formations[i].pcm))
  29                         continue;
  30 
  31                 t.min = min(t.min, snd_bebob_rate_table[i]);
  32                 t.max = max(t.max, snd_bebob_rate_table[i]);
  33 
  34         }
  35         return snd_interval_refine(r, &t);
  36 }
  37 
  38 static int
  39 hw_rule_channels(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
  40 {
  41         struct snd_bebob_stream_formation *formations = rule->private;
  42         struct snd_interval *c =
  43                 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  44         const struct snd_interval *r =
  45                 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  46         struct snd_interval t = {
  47                 .min = UINT_MAX, .max = 0, .integer = 1
  48         };
  49 
  50         unsigned int i;
  51 
  52         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  53                 /* entry is invalid */
  54                 if (formations[i].pcm == 0)
  55                         continue;
  56 
  57                 if (!snd_interval_test(r, snd_bebob_rate_table[i]))
  58                         continue;
  59 
  60                 t.min = min(t.min, formations[i].pcm);
  61                 t.max = max(t.max, formations[i].pcm);
  62         }
  63 
  64         return snd_interval_refine(c, &t);
  65 }
  66 
  67 static void
  68 limit_channels_and_rates(struct snd_pcm_hardware *hw,
  69                          struct snd_bebob_stream_formation *formations)
  70 {
  71         unsigned int i;
  72 
  73         hw->channels_min = UINT_MAX;
  74         hw->channels_max = 0;
  75 
  76         hw->rate_min = UINT_MAX;
  77         hw->rate_max = 0;
  78         hw->rates = 0;
  79 
  80         for (i = 0; i < SND_BEBOB_STRM_FMT_ENTRIES; i++) {
  81                 /* entry has no PCM channels */
  82                 if (formations[i].pcm == 0)
  83                         continue;
  84 
  85                 hw->channels_min = min(hw->channels_min, formations[i].pcm);
  86                 hw->channels_max = max(hw->channels_max, formations[i].pcm);
  87 
  88                 hw->rate_min = min(hw->rate_min, snd_bebob_rate_table[i]);
  89                 hw->rate_max = max(hw->rate_max, snd_bebob_rate_table[i]);
  90                 hw->rates |= snd_pcm_rate_to_rate_bit(snd_bebob_rate_table[i]);
  91         }
  92 }
  93 
  94 static int
  95 pcm_init_hw_params(struct snd_bebob *bebob,
  96                    struct snd_pcm_substream *substream)
  97 {
  98         struct snd_pcm_runtime *runtime = substream->runtime;
  99         struct amdtp_stream *s;
 100         struct snd_bebob_stream_formation *formations;
 101         int err;
 102 
 103         if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 104                 runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
 105                 s = &bebob->tx_stream;
 106                 formations = bebob->tx_stream_formations;
 107         } else {
 108                 runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
 109                 s = &bebob->rx_stream;
 110                 formations = bebob->rx_stream_formations;
 111         }
 112 
 113         limit_channels_and_rates(&runtime->hw, formations);
 114 
 115         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 116                                   hw_rule_channels, formations,
 117                                   SNDRV_PCM_HW_PARAM_RATE, -1);
 118         if (err < 0)
 119                 goto end;
 120 
 121         err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 122                                   hw_rule_rate, formations,
 123                                   SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 124         if (err < 0)
 125                 goto end;
 126 
 127         err = amdtp_am824_add_pcm_hw_constraints(s, runtime);
 128 end:
 129         return err;
 130 }
 131 
 132 static int
 133 pcm_open(struct snd_pcm_substream *substream)
 134 {
 135         struct snd_bebob *bebob = substream->private_data;
 136         const struct snd_bebob_rate_spec *spec = bebob->spec->rate;
 137         unsigned int sampling_rate;
 138         enum snd_bebob_clock_type src;
 139         int err;
 140 
 141         err = snd_bebob_stream_lock_try(bebob);
 142         if (err < 0)
 143                 goto end;
 144 
 145         err = pcm_init_hw_params(bebob, substream);
 146         if (err < 0)
 147                 goto err_locked;
 148 
 149         err = snd_bebob_stream_get_clock_src(bebob, &src);
 150         if (err < 0)
 151                 goto err_locked;
 152 
 153         /*
 154          * When source of clock is internal or any PCM stream are running,
 155          * the available sampling rate is limited at current sampling rate.
 156          */
 157         if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
 158             amdtp_stream_pcm_running(&bebob->tx_stream) ||
 159             amdtp_stream_pcm_running(&bebob->rx_stream)) {
 160                 err = spec->get(bebob, &sampling_rate);
 161                 if (err < 0) {
 162                         dev_err(&bebob->unit->device,
 163                                 "fail to get sampling rate: %d\n", err);
 164                         goto err_locked;
 165                 }
 166 
 167                 substream->runtime->hw.rate_min = sampling_rate;
 168                 substream->runtime->hw.rate_max = sampling_rate;
 169         }
 170 
 171         snd_pcm_set_sync(substream);
 172 end:
 173         return err;
 174 err_locked:
 175         snd_bebob_stream_lock_release(bebob);
 176         return err;
 177 }
 178 
 179 static int
 180 pcm_close(struct snd_pcm_substream *substream)
 181 {
 182         struct snd_bebob *bebob = substream->private_data;
 183         snd_bebob_stream_lock_release(bebob);
 184         return 0;
 185 }
 186 
 187 static int pcm_hw_params(struct snd_pcm_substream *substream,
 188                          struct snd_pcm_hw_params *hw_params)
 189 {
 190         struct snd_bebob *bebob = substream->private_data;
 191         int err;
 192 
 193         err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 194                                                params_buffer_bytes(hw_params));
 195         if (err < 0)
 196                 return err;
 197 
 198         if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 199                 unsigned int rate = params_rate(hw_params);
 200 
 201                 mutex_lock(&bebob->mutex);
 202                 err = snd_bebob_stream_reserve_duplex(bebob, rate);
 203                 if (err >= 0)
 204                         ++bebob->substreams_counter;
 205                 mutex_unlock(&bebob->mutex);
 206         }
 207 
 208         return err;
 209 }
 210 
 211 static int pcm_hw_free(struct snd_pcm_substream *substream)
 212 {
 213         struct snd_bebob *bebob = substream->private_data;
 214 
 215         mutex_lock(&bebob->mutex);
 216 
 217         if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 218                 bebob->substreams_counter--;
 219 
 220         snd_bebob_stream_stop_duplex(bebob);
 221 
 222         mutex_unlock(&bebob->mutex);
 223 
 224         return snd_pcm_lib_free_vmalloc_buffer(substream);
 225 }
 226 
 227 static int
 228 pcm_capture_prepare(struct snd_pcm_substream *substream)
 229 {
 230         struct snd_bebob *bebob = substream->private_data;
 231         int err;
 232 
 233         err = snd_bebob_stream_start_duplex(bebob);
 234         if (err >= 0)
 235                 amdtp_stream_pcm_prepare(&bebob->tx_stream);
 236 
 237         return err;
 238 }
 239 static int
 240 pcm_playback_prepare(struct snd_pcm_substream *substream)
 241 {
 242         struct snd_bebob *bebob = substream->private_data;
 243         int err;
 244 
 245         err = snd_bebob_stream_start_duplex(bebob);
 246         if (err >= 0)
 247                 amdtp_stream_pcm_prepare(&bebob->rx_stream);
 248 
 249         return err;
 250 }
 251 
 252 static int
 253 pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 254 {
 255         struct snd_bebob *bebob = substream->private_data;
 256 
 257         switch (cmd) {
 258         case SNDRV_PCM_TRIGGER_START:
 259                 amdtp_stream_pcm_trigger(&bebob->tx_stream, substream);
 260                 break;
 261         case SNDRV_PCM_TRIGGER_STOP:
 262                 amdtp_stream_pcm_trigger(&bebob->tx_stream, NULL);
 263                 break;
 264         default:
 265                 return -EINVAL;
 266         }
 267 
 268         return 0;
 269 }
 270 static int
 271 pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 272 {
 273         struct snd_bebob *bebob = substream->private_data;
 274 
 275         switch (cmd) {
 276         case SNDRV_PCM_TRIGGER_START:
 277                 amdtp_stream_pcm_trigger(&bebob->rx_stream, substream);
 278                 break;
 279         case SNDRV_PCM_TRIGGER_STOP:
 280                 amdtp_stream_pcm_trigger(&bebob->rx_stream, NULL);
 281                 break;
 282         default:
 283                 return -EINVAL;
 284         }
 285 
 286         return 0;
 287 }
 288 
 289 static snd_pcm_uframes_t
 290 pcm_capture_pointer(struct snd_pcm_substream *sbstrm)
 291 {
 292         struct snd_bebob *bebob = sbstrm->private_data;
 293         return amdtp_stream_pcm_pointer(&bebob->tx_stream);
 294 }
 295 static snd_pcm_uframes_t
 296 pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
 297 {
 298         struct snd_bebob *bebob = sbstrm->private_data;
 299         return amdtp_stream_pcm_pointer(&bebob->rx_stream);
 300 }
 301 
 302 static int pcm_capture_ack(struct snd_pcm_substream *substream)
 303 {
 304         struct snd_bebob *bebob = substream->private_data;
 305 
 306         return amdtp_stream_pcm_ack(&bebob->tx_stream);
 307 }
 308 
 309 static int pcm_playback_ack(struct snd_pcm_substream *substream)
 310 {
 311         struct snd_bebob *bebob = substream->private_data;
 312 
 313         return amdtp_stream_pcm_ack(&bebob->rx_stream);
 314 }
 315 
 316 int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
 317 {
 318         static const struct snd_pcm_ops capture_ops = {
 319                 .open           = pcm_open,
 320                 .close          = pcm_close,
 321                 .ioctl          = snd_pcm_lib_ioctl,
 322                 .hw_params      = pcm_hw_params,
 323                 .hw_free        = pcm_hw_free,
 324                 .prepare        = pcm_capture_prepare,
 325                 .trigger        = pcm_capture_trigger,
 326                 .pointer        = pcm_capture_pointer,
 327                 .ack            = pcm_capture_ack,
 328                 .page           = snd_pcm_lib_get_vmalloc_page,
 329         };
 330         static const struct snd_pcm_ops playback_ops = {
 331                 .open           = pcm_open,
 332                 .close          = pcm_close,
 333                 .ioctl          = snd_pcm_lib_ioctl,
 334                 .hw_params      = pcm_hw_params,
 335                 .hw_free        = pcm_hw_free,
 336                 .prepare        = pcm_playback_prepare,
 337                 .trigger        = pcm_playback_trigger,
 338                 .pointer        = pcm_playback_pointer,
 339                 .ack            = pcm_playback_ack,
 340                 .page           = snd_pcm_lib_get_vmalloc_page,
 341         };
 342         struct snd_pcm *pcm;
 343         int err;
 344 
 345         err = snd_pcm_new(bebob->card, bebob->card->driver, 0, 1, 1, &pcm);
 346         if (err < 0)
 347                 goto end;
 348 
 349         pcm->private_data = bebob;
 350         snprintf(pcm->name, sizeof(pcm->name),
 351                  "%s PCM", bebob->card->shortname);
 352         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
 353         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 354 end:
 355         return err;
 356 }

/* [<][>][^][v][top][bottom][index][help] */