linux/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Driver for Sound Core PDAudioCF soundcards
   4 *
   5 * PCM part
   6 *
   7 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
   8 */
   9
  10#include <linux/delay.h>
  11#include <sound/core.h>
  12#include <sound/asoundef.h>
  13#include "pdaudiocf.h"
  14
  15
  16/*
  17 * clear the SRAM contents
  18 */
  19static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)
  20{
  21        int max_loop = 64 * 1024;
  22
  23        while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
  24                if (max_loop-- < 0)
  25                        return -EIO;
  26                inw(chip->port + PDAUDIOCF_REG_MD);
  27        }
  28        return 0;
  29}
  30
  31/*
  32 * pdacf_pcm_trigger - trigger callback for capture
  33 */
  34static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
  35{
  36        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
  37        struct snd_pcm_runtime *runtime = subs->runtime;
  38        int inc, ret = 0, rate;
  39        unsigned short mask, val, tmp;
  40
  41        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
  42                return -EBUSY;
  43
  44        switch (cmd) {
  45        case SNDRV_PCM_TRIGGER_START:
  46                chip->pcm_hwptr = 0;
  47                chip->pcm_tdone = 0;
  48                fallthrough;
  49        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  50        case SNDRV_PCM_TRIGGER_RESUME:
  51                mask = 0;
  52                val = PDAUDIOCF_RECORD;
  53                inc = 1;
  54                rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
  55                break;
  56        case SNDRV_PCM_TRIGGER_STOP:
  57        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  58        case SNDRV_PCM_TRIGGER_SUSPEND:
  59                mask = PDAUDIOCF_RECORD;
  60                val = 0;
  61                inc = -1;
  62                rate = 0;
  63                break;
  64        default:
  65                return -EINVAL;
  66        }
  67        mutex_lock(&chip->reg_lock);
  68        chip->pcm_running += inc;
  69        tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
  70        if (chip->pcm_running) {
  71                if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
  72                        chip->pcm_running -= inc;
  73                        ret = -EIO;
  74                        goto __end;
  75                }
  76        }
  77        tmp &= ~mask;
  78        tmp |= val;
  79        pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
  80      __end:
  81        mutex_unlock(&chip->reg_lock);
  82        snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
  83        return ret;
  84}
  85
  86/*
  87 * pdacf_pcm_prepare - prepare callback for playback and capture
  88 */
  89static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)
  90{
  91        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
  92        struct snd_pcm_runtime *runtime = subs->runtime;
  93        u16 val, nval, aval;
  94
  95        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
  96                return -EBUSY;
  97
  98        chip->pcm_channels = runtime->channels;
  99
 100        chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
 101#ifdef SNDRV_LITTLE_ENDIAN
 102        chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
 103#else
 104        chip->pcm_swab = chip->pcm_little;
 105#endif
 106
 107        if (snd_pcm_format_unsigned(runtime->format))
 108                chip->pcm_xor = 0x80008000;
 109
 110        if (pdacf_pcm_clear_sram(chip) < 0)
 111                return -EIO;
 112        
 113        val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
 114        nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
 115        switch (runtime->format) {
 116        case SNDRV_PCM_FORMAT_S16_LE:
 117        case SNDRV_PCM_FORMAT_S16_BE:
 118                break;
 119        default: /* 24-bit */
 120                nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
 121                break;
 122        }
 123        aval = 0;
 124        chip->pcm_sample = 4;
 125        switch (runtime->format) {
 126        case SNDRV_PCM_FORMAT_S16_LE:
 127        case SNDRV_PCM_FORMAT_S16_BE:
 128                aval = AK4117_DIF_16R;
 129                chip->pcm_frame = 2;
 130                chip->pcm_sample = 2;
 131                break;
 132        case SNDRV_PCM_FORMAT_S24_3LE:
 133        case SNDRV_PCM_FORMAT_S24_3BE:
 134                chip->pcm_sample = 3;
 135                fallthrough;
 136        default: /* 24-bit */
 137                aval = AK4117_DIF_24R;
 138                chip->pcm_frame = 3;
 139                chip->pcm_xor &= 0xffff0000;
 140                break;
 141        }
 142
 143        if (val != nval) {
 144                snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
 145                pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
 146        }
 147
 148        val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);
 149        val &= ~(PDAUDIOCF_IRQLVLEN1);
 150        val |= PDAUDIOCF_IRQLVLEN0;
 151        pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
 152
 153        chip->pcm_size = runtime->buffer_size;
 154        chip->pcm_period = runtime->period_size;
 155        chip->pcm_area = runtime->dma_area;
 156
 157        return 0;
 158}
 159
 160
 161/*
 162 * capture hw information
 163 */
 164
 165static const struct snd_pcm_hardware pdacf_pcm_capture_hw = {
 166        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 167                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
 168                                 SNDRV_PCM_INFO_MMAP_VALID |
 169                                 SNDRV_PCM_INFO_BATCH),
 170        .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
 171                                SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
 172                                SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
 173        .rates =                SNDRV_PCM_RATE_32000 |
 174                                SNDRV_PCM_RATE_44100 |
 175                                SNDRV_PCM_RATE_48000 |
 176                                SNDRV_PCM_RATE_88200 |
 177                                SNDRV_PCM_RATE_96000 |
 178                                SNDRV_PCM_RATE_176400 |
 179                                SNDRV_PCM_RATE_192000,
 180        .rate_min =             32000,
 181        .rate_max =             192000,
 182        .channels_min =         1,
 183        .channels_max =         2,
 184        .buffer_bytes_max =     (512*1024),
 185        .period_bytes_min =     8*1024,
 186        .period_bytes_max =     (64*1024),
 187        .periods_min =          2,
 188        .periods_max =          128,
 189        .fifo_size =            0,
 190};
 191
 192
 193/*
 194 * pdacf_pcm_capture_open - open callback for capture
 195 */
 196static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)
 197{
 198        struct snd_pcm_runtime *runtime = subs->runtime;
 199        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 200
 201        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
 202                return -EBUSY;
 203
 204        runtime->hw = pdacf_pcm_capture_hw;
 205        runtime->private_data = chip;
 206        chip->pcm_substream = subs;
 207
 208        return 0;
 209}
 210
 211/*
 212 * pdacf_pcm_capture_close - close callback for capture
 213 */
 214static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)
 215{
 216        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 217
 218        if (!chip)
 219                return -EINVAL;
 220        pdacf_reinit(chip, 0);
 221        chip->pcm_substream = NULL;
 222        return 0;
 223}
 224
 225
 226/*
 227 * pdacf_pcm_capture_pointer - pointer callback for capture
 228 */
 229static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)
 230{
 231        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 232        return chip->pcm_hwptr;
 233}
 234
 235/*
 236 * operators for PCM capture
 237 */
 238static const struct snd_pcm_ops pdacf_pcm_capture_ops = {
 239        .open =         pdacf_pcm_capture_open,
 240        .close =        pdacf_pcm_capture_close,
 241        .prepare =      pdacf_pcm_prepare,
 242        .trigger =      pdacf_pcm_trigger,
 243        .pointer =      pdacf_pcm_capture_pointer,
 244};
 245
 246
 247/*
 248 * snd_pdacf_pcm_new - create and initialize a pcm
 249 */
 250int snd_pdacf_pcm_new(struct snd_pdacf *chip)
 251{
 252        struct snd_pcm *pcm;
 253        int err;
 254
 255        err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
 256        if (err < 0)
 257                return err;
 258                
 259        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
 260        snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC,
 261                                       snd_dma_continuous_data(GFP_KERNEL | GFP_DMA32),
 262                                       0, 0);
 263
 264        pcm->private_data = chip;
 265        pcm->info_flags = 0;
 266        pcm->nonatomic = true;
 267        strcpy(pcm->name, chip->card->shortname);
 268        chip->pcm = pcm;
 269        
 270        err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
 271        if (err < 0)
 272                return err;
 273
 274        return 0;
 275}
 276