linux/sound/pci/ctxfi/ctpcm.c
<<
>>
Prefs
   1/**
   2 * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved.
   3 *
   4 * This source file is released under GPL v2 license (no other versions).
   5 * See the COPYING file included in the main directory of this source
   6 * distribution for the license terms and conditions.
   7 *
   8 * @File        ctpcm.c
   9 *
  10 * @Brief
  11 * This file contains the definition of the pcm device functions.
  12 *
  13 * @Author      Liu Chun
  14 * @Date        Apr 2 2008
  15 *
  16 */
  17
  18#include "ctpcm.h"
  19#include "cttimer.h"
  20#include <sound/pcm.h>
  21
  22/* Hardware descriptions for playback */
  23static struct snd_pcm_hardware ct_pcm_playback_hw = {
  24        .info                   = (SNDRV_PCM_INFO_MMAP |
  25                                   SNDRV_PCM_INFO_INTERLEAVED |
  26                                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
  27                                   SNDRV_PCM_INFO_MMAP_VALID |
  28                                   SNDRV_PCM_INFO_PAUSE),
  29        .formats                = (SNDRV_PCM_FMTBIT_U8 |
  30                                   SNDRV_PCM_FMTBIT_S16_LE |
  31                                   SNDRV_PCM_FMTBIT_S24_3LE |
  32                                   SNDRV_PCM_FMTBIT_S32_LE |
  33                                   SNDRV_PCM_FMTBIT_FLOAT_LE),
  34        .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
  35                                   SNDRV_PCM_RATE_8000_192000),
  36        .rate_min               = 8000,
  37        .rate_max               = 192000,
  38        .channels_min           = 1,
  39        .channels_max           = 2,
  40        .buffer_bytes_max       = (128*1024),
  41        .period_bytes_min       = (64),
  42        .period_bytes_max       = (128*1024),
  43        .periods_min            = 2,
  44        .periods_max            = 1024,
  45        .fifo_size              = 0,
  46};
  47
  48static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = {
  49        .info                   = (SNDRV_PCM_INFO_MMAP |
  50                                   SNDRV_PCM_INFO_INTERLEAVED |
  51                                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
  52                                   SNDRV_PCM_INFO_MMAP_VALID |
  53                                   SNDRV_PCM_INFO_PAUSE),
  54        .formats                = SNDRV_PCM_FMTBIT_S16_LE,
  55        .rates                  = (SNDRV_PCM_RATE_48000 |
  56                                   SNDRV_PCM_RATE_44100 |
  57                                   SNDRV_PCM_RATE_32000),
  58        .rate_min               = 32000,
  59        .rate_max               = 48000,
  60        .channels_min           = 2,
  61        .channels_max           = 2,
  62        .buffer_bytes_max       = (128*1024),
  63        .period_bytes_min       = (64),
  64        .period_bytes_max       = (128*1024),
  65        .periods_min            = 2,
  66        .periods_max            = 1024,
  67        .fifo_size              = 0,
  68};
  69
  70/* Hardware descriptions for capture */
  71static struct snd_pcm_hardware ct_pcm_capture_hw = {
  72        .info                   = (SNDRV_PCM_INFO_MMAP |
  73                                   SNDRV_PCM_INFO_INTERLEAVED |
  74                                   SNDRV_PCM_INFO_BLOCK_TRANSFER |
  75                                   SNDRV_PCM_INFO_PAUSE |
  76                                   SNDRV_PCM_INFO_MMAP_VALID),
  77        .formats                = (SNDRV_PCM_FMTBIT_U8 |
  78                                   SNDRV_PCM_FMTBIT_S16_LE |
  79                                   SNDRV_PCM_FMTBIT_S24_3LE |
  80                                   SNDRV_PCM_FMTBIT_S32_LE |
  81                                   SNDRV_PCM_FMTBIT_FLOAT_LE),
  82        .rates                  = (SNDRV_PCM_RATE_CONTINUOUS |
  83                                   SNDRV_PCM_RATE_8000_96000),
  84        .rate_min               = 8000,
  85        .rate_max               = 96000,
  86        .channels_min           = 1,
  87        .channels_max           = 2,
  88        .buffer_bytes_max       = (128*1024),
  89        .period_bytes_min       = (384),
  90        .period_bytes_max       = (64*1024),
  91        .periods_min            = 2,
  92        .periods_max            = 1024,
  93        .fifo_size              = 0,
  94};
  95
  96static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm)
  97{
  98        struct ct_atc_pcm *apcm = atc_pcm;
  99
 100        if (!apcm->substream)
 101                return;
 102
 103        snd_pcm_period_elapsed(apcm->substream);
 104}
 105
 106static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime)
 107{
 108        struct ct_atc_pcm *apcm = runtime->private_data;
 109        struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream);
 110
 111        atc->pcm_release_resources(atc, apcm);
 112        ct_timer_instance_free(apcm->timer);
 113        kfree(apcm);
 114        runtime->private_data = NULL;
 115}
 116
 117/* pcm playback operations */
 118static int ct_pcm_playback_open(struct snd_pcm_substream *substream)
 119{
 120        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 121        struct snd_pcm_runtime *runtime = substream->runtime;
 122        struct ct_atc_pcm *apcm;
 123        int err;
 124
 125        apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 126        if (!apcm)
 127                return -ENOMEM;
 128
 129        apcm->substream = substream;
 130        apcm->interrupt = ct_atc_pcm_interrupt;
 131        runtime->private_data = apcm;
 132        runtime->private_free = ct_atc_pcm_free_substream;
 133        if (IEC958 == substream->pcm->device) {
 134                runtime->hw = ct_spdif_passthru_playback_hw;
 135                atc->spdif_out_passthru(atc, 1);
 136        } else {
 137                runtime->hw = ct_pcm_playback_hw;
 138                if (FRONT == substream->pcm->device)
 139                        runtime->hw.channels_max = 8;
 140        }
 141
 142        err = snd_pcm_hw_constraint_integer(runtime,
 143                                            SNDRV_PCM_HW_PARAM_PERIODS);
 144        if (err < 0) {
 145                kfree(apcm);
 146                return err;
 147        }
 148        err = snd_pcm_hw_constraint_minmax(runtime,
 149                                           SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 150                                           1024, UINT_MAX);
 151        if (err < 0) {
 152                kfree(apcm);
 153                return err;
 154        }
 155
 156        apcm->timer = ct_timer_instance_new(atc->timer, apcm);
 157        if (!apcm->timer)
 158                return -ENOMEM;
 159
 160        return 0;
 161}
 162
 163static int ct_pcm_playback_close(struct snd_pcm_substream *substream)
 164{
 165        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 166
 167        /* TODO: Notify mixer inactive. */
 168        if (IEC958 == substream->pcm->device)
 169                atc->spdif_out_passthru(atc, 0);
 170
 171        /* The ct_atc_pcm object will be freed by runtime->private_free */
 172
 173        return 0;
 174}
 175
 176static int ct_pcm_hw_params(struct snd_pcm_substream *substream,
 177                                     struct snd_pcm_hw_params *hw_params)
 178{
 179        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 180        struct ct_atc_pcm *apcm = substream->runtime->private_data;
 181        int err;
 182
 183        err = snd_pcm_lib_malloc_pages(substream,
 184                                        params_buffer_bytes(hw_params));
 185        if (err < 0)
 186                return err;
 187        /* clear previous resources */
 188        atc->pcm_release_resources(atc, apcm);
 189        return err;
 190}
 191
 192static int ct_pcm_hw_free(struct snd_pcm_substream *substream)
 193{
 194        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 195        struct ct_atc_pcm *apcm = substream->runtime->private_data;
 196
 197        /* clear previous resources */
 198        atc->pcm_release_resources(atc, apcm);
 199        /* Free snd-allocated pages */
 200        return snd_pcm_lib_free_pages(substream);
 201}
 202
 203
 204static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream)
 205{
 206        int err;
 207        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 208        struct snd_pcm_runtime *runtime = substream->runtime;
 209        struct ct_atc_pcm *apcm = runtime->private_data;
 210
 211        if (IEC958 == substream->pcm->device)
 212                err = atc->spdif_passthru_playback_prepare(atc, apcm);
 213        else
 214                err = atc->pcm_playback_prepare(atc, apcm);
 215
 216        if (err < 0) {
 217                printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n");
 218                return err;
 219        }
 220
 221        return 0;
 222}
 223
 224static int
 225ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 226{
 227        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 228        struct snd_pcm_runtime *runtime = substream->runtime;
 229        struct ct_atc_pcm *apcm = runtime->private_data;
 230
 231        switch (cmd) {
 232        case SNDRV_PCM_TRIGGER_START:
 233        case SNDRV_PCM_TRIGGER_RESUME:
 234        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 235                atc->pcm_playback_start(atc, apcm);
 236                break;
 237        case SNDRV_PCM_TRIGGER_STOP:
 238        case SNDRV_PCM_TRIGGER_SUSPEND:
 239        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 240                atc->pcm_playback_stop(atc, apcm);
 241                break;
 242        default:
 243                break;
 244        }
 245
 246        return 0;
 247}
 248
 249static snd_pcm_uframes_t
 250ct_pcm_playback_pointer(struct snd_pcm_substream *substream)
 251{
 252        unsigned long position;
 253        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 254        struct snd_pcm_runtime *runtime = substream->runtime;
 255        struct ct_atc_pcm *apcm = runtime->private_data;
 256
 257        /* Read out playback position */
 258        position = atc->pcm_playback_position(atc, apcm);
 259        position = bytes_to_frames(runtime, position);
 260        if (position >= runtime->buffer_size)
 261                position = 0;
 262        return position;
 263}
 264
 265/* pcm capture operations */
 266static int ct_pcm_capture_open(struct snd_pcm_substream *substream)
 267{
 268        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 269        struct snd_pcm_runtime *runtime = substream->runtime;
 270        struct ct_atc_pcm *apcm;
 271        int err;
 272
 273        apcm = kzalloc(sizeof(*apcm), GFP_KERNEL);
 274        if (!apcm)
 275                return -ENOMEM;
 276
 277        apcm->started = 0;
 278        apcm->substream = substream;
 279        apcm->interrupt = ct_atc_pcm_interrupt;
 280        runtime->private_data = apcm;
 281        runtime->private_free = ct_atc_pcm_free_substream;
 282        runtime->hw = ct_pcm_capture_hw;
 283        runtime->hw.rate_max = atc->rsr * atc->msr;
 284
 285        err = snd_pcm_hw_constraint_integer(runtime,
 286                                            SNDRV_PCM_HW_PARAM_PERIODS);
 287        if (err < 0) {
 288                kfree(apcm);
 289                return err;
 290        }
 291        err = snd_pcm_hw_constraint_minmax(runtime,
 292                                           SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
 293                                           1024, UINT_MAX);
 294        if (err < 0) {
 295                kfree(apcm);
 296                return err;
 297        }
 298
 299        apcm->timer = ct_timer_instance_new(atc->timer, apcm);
 300        if (!apcm->timer)
 301                return -ENOMEM;
 302
 303        return 0;
 304}
 305
 306static int ct_pcm_capture_close(struct snd_pcm_substream *substream)
 307{
 308        /* The ct_atc_pcm object will be freed by runtime->private_free */
 309        /* TODO: Notify mixer inactive. */
 310        return 0;
 311}
 312
 313static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream)
 314{
 315        int err;
 316        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 317        struct snd_pcm_runtime *runtime = substream->runtime;
 318        struct ct_atc_pcm *apcm = runtime->private_data;
 319
 320        err = atc->pcm_capture_prepare(atc, apcm);
 321        if (err < 0) {
 322                printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n");
 323                return err;
 324        }
 325
 326        return 0;
 327}
 328
 329static int
 330ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
 331{
 332        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 333        struct snd_pcm_runtime *runtime = substream->runtime;
 334        struct ct_atc_pcm *apcm = runtime->private_data;
 335
 336        switch (cmd) {
 337        case SNDRV_PCM_TRIGGER_START:
 338                atc->pcm_capture_start(atc, apcm);
 339                break;
 340        case SNDRV_PCM_TRIGGER_STOP:
 341                atc->pcm_capture_stop(atc, apcm);
 342                break;
 343        default:
 344                atc->pcm_capture_stop(atc, apcm);
 345                break;
 346        }
 347
 348        return 0;
 349}
 350
 351static snd_pcm_uframes_t
 352ct_pcm_capture_pointer(struct snd_pcm_substream *substream)
 353{
 354        unsigned long position;
 355        struct ct_atc *atc = snd_pcm_substream_chip(substream);
 356        struct snd_pcm_runtime *runtime = substream->runtime;
 357        struct ct_atc_pcm *apcm = runtime->private_data;
 358
 359        /* Read out playback position */
 360        position = atc->pcm_capture_position(atc, apcm);
 361        position = bytes_to_frames(runtime, position);
 362        if (position >= runtime->buffer_size)
 363                position = 0;
 364        return position;
 365}
 366
 367/* PCM operators for playback */
 368static struct snd_pcm_ops ct_pcm_playback_ops = {
 369        .open           = ct_pcm_playback_open,
 370        .close          = ct_pcm_playback_close,
 371        .ioctl          = snd_pcm_lib_ioctl,
 372        .hw_params      = ct_pcm_hw_params,
 373        .hw_free        = ct_pcm_hw_free,
 374        .prepare        = ct_pcm_playback_prepare,
 375        .trigger        = ct_pcm_playback_trigger,
 376        .pointer        = ct_pcm_playback_pointer,
 377        .page           = snd_pcm_sgbuf_ops_page,
 378};
 379
 380/* PCM operators for capture */
 381static struct snd_pcm_ops ct_pcm_capture_ops = {
 382        .open           = ct_pcm_capture_open,
 383        .close          = ct_pcm_capture_close,
 384        .ioctl          = snd_pcm_lib_ioctl,
 385        .hw_params      = ct_pcm_hw_params,
 386        .hw_free        = ct_pcm_hw_free,
 387        .prepare        = ct_pcm_capture_prepare,
 388        .trigger        = ct_pcm_capture_trigger,
 389        .pointer        = ct_pcm_capture_pointer,
 390        .page           = snd_pcm_sgbuf_ops_page,
 391};
 392
 393/* Create ALSA pcm device */
 394int ct_alsa_pcm_create(struct ct_atc *atc,
 395                       enum CTALSADEVS device,
 396                       const char *device_name)
 397{
 398        struct snd_pcm *pcm;
 399        int err;
 400        int playback_count, capture_count;
 401
 402        playback_count = (IEC958 == device) ? 1 : 8;
 403        capture_count = (FRONT == device) ? 1 : 0;
 404        err = snd_pcm_new(atc->card, "ctxfi", device,
 405                          playback_count, capture_count, &pcm);
 406        if (err < 0) {
 407                printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err);
 408                return err;
 409        }
 410
 411        pcm->private_data = atc;
 412        pcm->info_flags = 0;
 413        pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX;
 414        strlcpy(pcm->name, device_name, sizeof(pcm->name));
 415
 416        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops);
 417
 418        if (FRONT == device)
 419                snd_pcm_set_ops(pcm,
 420                                SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops);
 421
 422        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
 423                        snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 424
 425#ifdef CONFIG_PM
 426        atc->pcms[device] = pcm;
 427#endif
 428
 429        return 0;
 430}
 431