linux/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
<<
>>
Prefs
   1/*
   2 * Driver for Sound Core PDAudioCF soundcards
   3 *
   4 * PCM part
   5 *
   6 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
   7 *
   8 *   This program is free software; you can redistribute it and/or modify
   9 *   it under the terms of the GNU General Public License as published by
  10 *   the Free Software Foundation; either version 2 of the License, or
  11 *   (at your option) any later version.
  12 *
  13 *   This program is distributed in the hope that it will be useful,
  14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *   GNU General Public License for more details.
  17 *
  18 *   You should have received a copy of the GNU General Public License
  19 *   along with this program; if not, write to the Free Software
  20 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  21 */
  22
  23#include <linux/delay.h>
  24#include <sound/core.h>
  25#include <sound/asoundef.h>
  26#include "pdaudiocf.h"
  27
  28
  29/*
  30 * clear the SRAM contents
  31 */
  32static int pdacf_pcm_clear_sram(struct snd_pdacf *chip)
  33{
  34        int max_loop = 64 * 1024;
  35
  36        while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) {
  37                if (max_loop-- < 0)
  38                        return -EIO;
  39                inw(chip->port + PDAUDIOCF_REG_MD);
  40        }
  41        return 0;
  42}
  43
  44/*
  45 * pdacf_pcm_trigger - trigger callback for capture
  46 */
  47static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
  48{
  49        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
  50        struct snd_pcm_runtime *runtime = subs->runtime;
  51        int inc, ret = 0, rate;
  52        unsigned short mask, val, tmp;
  53
  54        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
  55                return -EBUSY;
  56
  57        switch (cmd) {
  58        case SNDRV_PCM_TRIGGER_START:
  59                chip->pcm_hwptr = 0;
  60                chip->pcm_tdone = 0;
  61                /* fall thru */
  62        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  63        case SNDRV_PCM_TRIGGER_RESUME:
  64                mask = 0;
  65                val = PDAUDIOCF_RECORD;
  66                inc = 1;
  67                rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE);
  68                break;
  69        case SNDRV_PCM_TRIGGER_STOP:
  70        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  71        case SNDRV_PCM_TRIGGER_SUSPEND:
  72                mask = PDAUDIOCF_RECORD;
  73                val = 0;
  74                inc = -1;
  75                rate = 0;
  76                break;
  77        default:
  78                return -EINVAL;
  79        }
  80        spin_lock(&chip->reg_lock);
  81        chip->pcm_running += inc;
  82        tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
  83        if (chip->pcm_running) {
  84                if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) {
  85                        chip->pcm_running -= inc;
  86                        ret = -EIO;
  87                        goto __end;
  88                }
  89        }
  90        tmp &= ~mask;
  91        tmp |= val;
  92        pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
  93      __end:
  94        spin_unlock(&chip->reg_lock);
  95        snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
  96        return ret;
  97}
  98
  99/*
 100 * pdacf_pcm_hw_params - hw_params callback for playback and capture
 101 */
 102static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs,
 103                                     struct snd_pcm_hw_params *hw_params)
 104{
 105        return snd_pcm_lib_alloc_vmalloc_32_buffer
 106                                        (subs, params_buffer_bytes(hw_params));
 107}
 108
 109/*
 110 * pdacf_pcm_hw_free - hw_free callback for playback and capture
 111 */
 112static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs)
 113{
 114        return snd_pcm_lib_free_vmalloc_buffer(subs);
 115}
 116
 117/*
 118 * pdacf_pcm_prepare - prepare callback for playback and capture
 119 */
 120static int pdacf_pcm_prepare(struct snd_pcm_substream *subs)
 121{
 122        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 123        struct snd_pcm_runtime *runtime = subs->runtime;
 124        u16 val, nval, aval;
 125
 126        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
 127                return -EBUSY;
 128
 129        chip->pcm_channels = runtime->channels;
 130
 131        chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0;
 132#ifdef SNDRV_LITTLE_ENDIAN
 133        chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0;
 134#else
 135        chip->pcm_swab = chip->pcm_little;
 136#endif
 137
 138        if (snd_pcm_format_unsigned(runtime->format))
 139                chip->pcm_xor = 0x80008000;
 140
 141        if (pdacf_pcm_clear_sram(chip) < 0)
 142                return -EIO;
 143        
 144        val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
 145        nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1);
 146        switch (runtime->format) {
 147        case SNDRV_PCM_FORMAT_S16_LE:
 148        case SNDRV_PCM_FORMAT_S16_BE:
 149                break;
 150        default: /* 24-bit */
 151                nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1;
 152                break;
 153        }
 154        aval = 0;
 155        chip->pcm_sample = 4;
 156        switch (runtime->format) {
 157        case SNDRV_PCM_FORMAT_S16_LE:
 158        case SNDRV_PCM_FORMAT_S16_BE:
 159                aval = AK4117_DIF_16R;
 160                chip->pcm_frame = 2;
 161                chip->pcm_sample = 2;
 162                break;
 163        case SNDRV_PCM_FORMAT_S24_3LE:
 164        case SNDRV_PCM_FORMAT_S24_3BE:
 165                chip->pcm_sample = 3;
 166                /* fall through */
 167        default: /* 24-bit */
 168                aval = AK4117_DIF_24R;
 169                chip->pcm_frame = 3;
 170                chip->pcm_xor &= 0xffff0000;
 171                break;
 172        }
 173
 174        if (val != nval) {
 175                snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval);
 176                pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval);
 177        }
 178
 179        val = pdacf_reg_read(chip,  PDAUDIOCF_REG_IER);
 180        val &= ~(PDAUDIOCF_IRQLVLEN1);
 181        val |= PDAUDIOCF_IRQLVLEN0;
 182        pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val);
 183
 184        chip->pcm_size = runtime->buffer_size;
 185        chip->pcm_period = runtime->period_size;
 186        chip->pcm_area = runtime->dma_area;
 187
 188        return 0;
 189}
 190
 191
 192/*
 193 * capture hw information
 194 */
 195
 196static struct snd_pcm_hardware pdacf_pcm_capture_hw = {
 197        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
 198                                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
 199                                 SNDRV_PCM_INFO_MMAP_VALID |
 200                                 SNDRV_PCM_INFO_BATCH),
 201        .formats =              SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
 202                                SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
 203                                SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE,
 204        .rates =                SNDRV_PCM_RATE_32000 |
 205                                SNDRV_PCM_RATE_44100 |
 206                                SNDRV_PCM_RATE_48000 |
 207                                SNDRV_PCM_RATE_88200 |
 208                                SNDRV_PCM_RATE_96000 |
 209                                SNDRV_PCM_RATE_176400 |
 210                                SNDRV_PCM_RATE_192000,
 211        .rate_min =             32000,
 212        .rate_max =             192000,
 213        .channels_min =         1,
 214        .channels_max =         2,
 215        .buffer_bytes_max =     (512*1024),
 216        .period_bytes_min =     8*1024,
 217        .period_bytes_max =     (64*1024),
 218        .periods_min =          2,
 219        .periods_max =          128,
 220        .fifo_size =            0,
 221};
 222
 223
 224/*
 225 * pdacf_pcm_capture_open - open callback for capture
 226 */
 227static int pdacf_pcm_capture_open(struct snd_pcm_substream *subs)
 228{
 229        struct snd_pcm_runtime *runtime = subs->runtime;
 230        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 231
 232        if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE)
 233                return -EBUSY;
 234
 235        runtime->hw = pdacf_pcm_capture_hw;
 236        runtime->private_data = chip;
 237        chip->pcm_substream = subs;
 238
 239        return 0;
 240}
 241
 242/*
 243 * pdacf_pcm_capture_close - close callback for capture
 244 */
 245static int pdacf_pcm_capture_close(struct snd_pcm_substream *subs)
 246{
 247        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 248
 249        if (!chip)
 250                return -EINVAL;
 251        pdacf_reinit(chip, 0);
 252        chip->pcm_substream = NULL;
 253        return 0;
 254}
 255
 256
 257/*
 258 * pdacf_pcm_capture_pointer - pointer callback for capture
 259 */
 260static snd_pcm_uframes_t pdacf_pcm_capture_pointer(struct snd_pcm_substream *subs)
 261{
 262        struct snd_pdacf *chip = snd_pcm_substream_chip(subs);
 263        return chip->pcm_hwptr;
 264}
 265
 266/*
 267 * operators for PCM capture
 268 */
 269static struct snd_pcm_ops pdacf_pcm_capture_ops = {
 270        .open =         pdacf_pcm_capture_open,
 271        .close =        pdacf_pcm_capture_close,
 272        .ioctl =        snd_pcm_lib_ioctl,
 273        .hw_params =    pdacf_pcm_hw_params,
 274        .hw_free =      pdacf_pcm_hw_free,
 275        .prepare =      pdacf_pcm_prepare,
 276        .trigger =      pdacf_pcm_trigger,
 277        .pointer =      pdacf_pcm_capture_pointer,
 278        .page =         snd_pcm_lib_get_vmalloc_page,
 279        .mmap =         snd_pcm_lib_mmap_vmalloc,
 280};
 281
 282
 283/*
 284 * snd_pdacf_pcm_new - create and initialize a pcm
 285 */
 286int snd_pdacf_pcm_new(struct snd_pdacf *chip)
 287{
 288        struct snd_pcm *pcm;
 289        int err;
 290
 291        err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm);
 292        if (err < 0)
 293                return err;
 294                
 295        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops);
 296
 297        pcm->private_data = chip;
 298        pcm->info_flags = 0;
 299        strcpy(pcm->name, chip->card->shortname);
 300        chip->pcm = pcm;
 301        
 302        err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
 303        if (err < 0)
 304                return err;
 305
 306        return 0;
 307}
 308