linux/sound/firewire/oxfw/oxfw-pcm.c
<<
>>
Prefs
   1/*
   2 * oxfw_pcm.c - a part of driver for OXFW970/971 based devices
   3 *
   4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   5 * Licensed under the terms of the GNU General Public License, version 2.
   6 */
   7
   8#include "oxfw.h"
   9
  10static int hw_rule_rate(struct snd_pcm_hw_params *params,
  11                        struct snd_pcm_hw_rule *rule)
  12{
  13        u8 **formats = 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        struct snd_oxfw_stream_formation formation;
  22        int i, err;
  23
  24        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
  25                if (formats[i] == NULL)
  26                        continue;
  27
  28                err = snd_oxfw_stream_parse_format(formats[i], &formation);
  29                if (err < 0)
  30                        continue;
  31                if (!snd_interval_test(c, formation.pcm))
  32                        continue;
  33
  34                t.min = min(t.min, formation.rate);
  35                t.max = max(t.max, formation.rate);
  36
  37        }
  38        return snd_interval_refine(r, &t);
  39}
  40
  41static int hw_rule_channels(struct snd_pcm_hw_params *params,
  42                            struct snd_pcm_hw_rule *rule)
  43{
  44        u8 **formats = rule->private;
  45        struct snd_interval *c =
  46                hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
  47        const struct snd_interval *r =
  48                hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
  49        struct snd_oxfw_stream_formation formation;
  50        int i, j, err;
  51        unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0};
  52
  53        count = 0;
  54        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
  55                if (formats[i] == NULL)
  56                        break;
  57
  58                err = snd_oxfw_stream_parse_format(formats[i], &formation);
  59                if (err < 0)
  60                        continue;
  61                if (!snd_interval_test(r, formation.rate))
  62                        continue;
  63                if (list[count] == formation.pcm)
  64                        continue;
  65
  66                for (j = 0; j < ARRAY_SIZE(list); j++) {
  67                        if (list[j] == formation.pcm)
  68                                break;
  69                }
  70                if (j == ARRAY_SIZE(list)) {
  71                        list[count] = formation.pcm;
  72                        if (++count == ARRAY_SIZE(list))
  73                                break;
  74                }
  75        }
  76
  77        return snd_interval_list(c, count, list, 0);
  78}
  79
  80static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats)
  81{
  82        struct snd_oxfw_stream_formation formation;
  83        int i, err;
  84
  85        hw->channels_min = UINT_MAX;
  86        hw->channels_max = 0;
  87
  88        hw->rate_min = UINT_MAX;
  89        hw->rate_max = 0;
  90        hw->rates = 0;
  91
  92        for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
  93                if (formats[i] == NULL)
  94                        break;
  95
  96                err = snd_oxfw_stream_parse_format(formats[i], &formation);
  97                if (err < 0)
  98                        continue;
  99
 100                hw->channels_min = min(hw->channels_min, formation.pcm);
 101                hw->channels_max = max(hw->channels_max, formation.pcm);
 102
 103                hw->rate_min = min(hw->rate_min, formation.rate);
 104                hw->rate_max = max(hw->rate_max, formation.rate);
 105                hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate);
 106        }
 107}
 108
 109static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
 110{
 111        hw->periods_min = 2;            /* SNDRV_PCM_INFO_BATCH */
 112        hw->periods_max = UINT_MAX;
 113
 114        hw->period_bytes_min = 4 * hw->channels_max;    /* bytes for a frame */
 115
 116        /* Just to prevent from allocating much pages. */
 117        hw->period_bytes_max = hw->period_bytes_min * 2048;
 118        hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
 119}
 120
 121static int init_hw_params(struct snd_oxfw *oxfw,
 122                          struct snd_pcm_substream *substream)
 123{
 124        struct snd_pcm_runtime *runtime = substream->runtime;
 125        u8 **formats;
 126        struct amdtp_stream *stream;
 127        int err;
 128
 129        runtime->hw.info = SNDRV_PCM_INFO_BATCH |
 130                           SNDRV_PCM_INFO_BLOCK_TRANSFER |
 131                           SNDRV_PCM_INFO_INTERLEAVED |
 132                           SNDRV_PCM_INFO_JOINT_DUPLEX |
 133                           SNDRV_PCM_INFO_MMAP |
 134                           SNDRV_PCM_INFO_MMAP_VALID;
 135
 136        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
 137                runtime->hw.formats = AM824_IN_PCM_FORMAT_BITS;
 138                stream = &oxfw->tx_stream;
 139                formats = oxfw->tx_stream_formats;
 140        } else {
 141                runtime->hw.formats = AM824_OUT_PCM_FORMAT_BITS;
 142                stream = &oxfw->rx_stream;
 143                formats = oxfw->rx_stream_formats;
 144        }
 145
 146        limit_channels_and_rates(&runtime->hw, formats);
 147        limit_period_and_buffer(&runtime->hw);
 148
 149        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
 150                                  hw_rule_channels, formats,
 151                                  SNDRV_PCM_HW_PARAM_RATE, -1);
 152        if (err < 0)
 153                goto end;
 154
 155        err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 156                                  hw_rule_rate, formats,
 157                                  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
 158        if (err < 0)
 159                goto end;
 160
 161        err = amdtp_am824_add_pcm_hw_constraints(stream, runtime);
 162end:
 163        return err;
 164}
 165
 166static int limit_to_current_params(struct snd_pcm_substream *substream)
 167{
 168        struct snd_oxfw *oxfw = substream->private_data;
 169        struct snd_oxfw_stream_formation formation;
 170        enum avc_general_plug_dir dir;
 171        int err;
 172
 173        if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 174                dir = AVC_GENERAL_PLUG_DIR_OUT;
 175        else
 176                dir = AVC_GENERAL_PLUG_DIR_IN;
 177
 178        err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
 179        if (err < 0)
 180                goto end;
 181
 182        substream->runtime->hw.channels_min = formation.pcm;
 183        substream->runtime->hw.channels_max = formation.pcm;
 184        substream->runtime->hw.rate_min = formation.rate;
 185        substream->runtime->hw.rate_max = formation.rate;
 186end:
 187        return err;
 188}
 189
 190static int pcm_open(struct snd_pcm_substream *substream)
 191{
 192        struct snd_oxfw *oxfw = substream->private_data;
 193        int err;
 194
 195        err = snd_oxfw_stream_lock_try(oxfw);
 196        if (err < 0)
 197                goto end;
 198
 199        err = init_hw_params(oxfw, substream);
 200        if (err < 0)
 201                goto err_locked;
 202
 203        /*
 204         * When any PCM streams are already running, the available sampling
 205         * rate is limited at current value.
 206         */
 207        if (amdtp_stream_pcm_running(&oxfw->tx_stream) ||
 208            amdtp_stream_pcm_running(&oxfw->rx_stream)) {
 209                err = limit_to_current_params(substream);
 210                if (err < 0)
 211                        goto end;
 212        }
 213
 214        snd_pcm_set_sync(substream);
 215end:
 216        return err;
 217err_locked:
 218        snd_oxfw_stream_lock_release(oxfw);
 219        return err;
 220}
 221
 222static int pcm_close(struct snd_pcm_substream *substream)
 223{
 224        struct snd_oxfw *oxfw = substream->private_data;
 225
 226        snd_oxfw_stream_lock_release(oxfw);
 227        return 0;
 228}
 229
 230static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
 231                                 struct snd_pcm_hw_params *hw_params)
 232{
 233        struct snd_oxfw *oxfw = substream->private_data;
 234        int err;
 235
 236        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 237                                               params_buffer_bytes(hw_params));
 238        if (err < 0)
 239                return err;
 240
 241        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 242                mutex_lock(&oxfw->mutex);
 243                oxfw->capture_substreams++;
 244                mutex_unlock(&oxfw->mutex);
 245        }
 246
 247        amdtp_am824_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
 248
 249        return 0;
 250}
 251static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
 252                                  struct snd_pcm_hw_params *hw_params)
 253{
 254        struct snd_oxfw *oxfw = substream->private_data;
 255        int err;
 256
 257        err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
 258                                               params_buffer_bytes(hw_params));
 259        if (err < 0)
 260                return err;
 261
 262        if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
 263                mutex_lock(&oxfw->mutex);
 264                oxfw->playback_substreams++;
 265                mutex_unlock(&oxfw->mutex);
 266        }
 267
 268        amdtp_am824_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
 269
 270        return 0;
 271}
 272
 273static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
 274{
 275        struct snd_oxfw *oxfw = substream->private_data;
 276
 277        mutex_lock(&oxfw->mutex);
 278
 279        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 280                oxfw->capture_substreams--;
 281
 282        snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
 283
 284        mutex_unlock(&oxfw->mutex);
 285
 286        return snd_pcm_lib_free_vmalloc_buffer(substream);
 287}
 288static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
 289{
 290        struct snd_oxfw *oxfw = substream->private_data;
 291
 292        mutex_lock(&oxfw->mutex);
 293
 294        if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
 295                oxfw->playback_substreams--;
 296
 297        snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
 298
 299        mutex_unlock(&oxfw->mutex);
 300
 301        return snd_pcm_lib_free_vmalloc_buffer(substream);
 302}
 303
 304static int pcm_capture_prepare(struct snd_pcm_substream *substream)
 305{
 306        struct snd_oxfw *oxfw = substream->private_data;
 307        struct snd_pcm_runtime *runtime = substream->runtime;
 308        int err;
 309
 310        mutex_lock(&oxfw->mutex);
 311        err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream,
 312                                            runtime->rate, runtime->channels);
 313        mutex_unlock(&oxfw->mutex);
 314        if (err < 0)
 315                goto end;
 316
 317        amdtp_stream_pcm_prepare(&oxfw->tx_stream);
 318end:
 319        return err;
 320}
 321static int pcm_playback_prepare(struct snd_pcm_substream *substream)
 322{
 323        struct snd_oxfw *oxfw = substream->private_data;
 324        struct snd_pcm_runtime *runtime = substream->runtime;
 325        int err;
 326
 327        mutex_lock(&oxfw->mutex);
 328        err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
 329                                            runtime->rate, runtime->channels);
 330        mutex_unlock(&oxfw->mutex);
 331        if (err < 0)
 332                goto end;
 333
 334        amdtp_stream_pcm_prepare(&oxfw->rx_stream);
 335end:
 336        return err;
 337}
 338
 339static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 340{
 341        struct snd_oxfw *oxfw = substream->private_data;
 342        struct snd_pcm_substream *pcm;
 343
 344        switch (cmd) {
 345        case SNDRV_PCM_TRIGGER_START:
 346                pcm = substream;
 347                break;
 348        case SNDRV_PCM_TRIGGER_STOP:
 349                pcm = NULL;
 350                break;
 351        default:
 352                return -EINVAL;
 353        }
 354        amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm);
 355        return 0;
 356}
 357static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 358{
 359        struct snd_oxfw *oxfw = substream->private_data;
 360        struct snd_pcm_substream *pcm;
 361
 362        switch (cmd) {
 363        case SNDRV_PCM_TRIGGER_START:
 364                pcm = substream;
 365                break;
 366        case SNDRV_PCM_TRIGGER_STOP:
 367                pcm = NULL;
 368                break;
 369        default:
 370                return -EINVAL;
 371        }
 372        amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
 373        return 0;
 374}
 375
 376static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
 377{
 378        struct snd_oxfw *oxfw = sbstm->private_data;
 379
 380        return amdtp_stream_pcm_pointer(&oxfw->tx_stream);
 381}
 382static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
 383{
 384        struct snd_oxfw *oxfw = sbstm->private_data;
 385
 386        return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
 387}
 388
 389int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
 390{
 391        static const struct snd_pcm_ops capture_ops = {
 392                .open      = pcm_open,
 393                .close     = pcm_close,
 394                .ioctl     = snd_pcm_lib_ioctl,
 395                .hw_params = pcm_capture_hw_params,
 396                .hw_free   = pcm_capture_hw_free,
 397                .prepare   = pcm_capture_prepare,
 398                .trigger   = pcm_capture_trigger,
 399                .pointer   = pcm_capture_pointer,
 400                .page      = snd_pcm_lib_get_vmalloc_page,
 401                .mmap      = snd_pcm_lib_mmap_vmalloc,
 402        };
 403        static const struct snd_pcm_ops playback_ops = {
 404                .open      = pcm_open,
 405                .close     = pcm_close,
 406                .ioctl     = snd_pcm_lib_ioctl,
 407                .hw_params = pcm_playback_hw_params,
 408                .hw_free   = pcm_playback_hw_free,
 409                .prepare   = pcm_playback_prepare,
 410                .trigger   = pcm_playback_trigger,
 411                .pointer   = pcm_playback_pointer,
 412                .page      = snd_pcm_lib_get_vmalloc_page,
 413                .mmap      = snd_pcm_lib_mmap_vmalloc,
 414        };
 415        struct snd_pcm *pcm;
 416        unsigned int cap = 0;
 417        int err;
 418
 419        if (oxfw->has_output)
 420                cap = 1;
 421
 422        err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm);
 423        if (err < 0)
 424                return err;
 425
 426        pcm->private_data = oxfw;
 427        strcpy(pcm->name, oxfw->card->shortname);
 428        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
 429        if (cap > 0)
 430                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 431
 432        return 0;
 433}
 434