Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  au88x0_pcm.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 */

 
/*
 * Vortex PCM ALSA driver.
 *
 * Supports ADB and WT DMA. Unfortunately, WT channels do not run yet.
 * It remains stuck,and DMA transfers do not happen. 
 */

#include <sound/asoundef.h>
#include <linux/time.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "au88x0.h"

#define VORTEX_PCM_TYPE(x) (x->name[40])

/* hardware definition */
static const struct snd_pcm_hardware snd_vortex_playback_hw_adb = {
 .info =
     (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
      SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
      SNDRV_PCM_INFO_MMAP_VALID),
 .formats =
     SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
     SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
 .rates = SNDRV_PCM_RATE_CONTINUOUS,
 .rate_min = 5000,
 .rate_max = 48000,
 .channels_min = 1,
 .channels_max = 2,
 .buffer_bytes_max = 0x10000,
 .period_bytes_min = 0x20,
 .period_bytes_max = 0x1000,
 .periods_min = 2,
 .periods_max = 1024,
};

#ifndef CHIP_AU8820
static const struct snd_pcm_hardware snd_vortex_playback_hw_a3d = {
 .info =
     (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
      SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
      SNDRV_PCM_INFO_MMAP_VALID),
 .formats =
     SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
     SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW,
 .rates = SNDRV_PCM_RATE_CONTINUOUS,
 .rate_min = 5000,
 .rate_max = 48000,
 .channels_min = 1,
 .channels_max = 1,
 .buffer_bytes_max = 0x10000,
 .period_bytes_min = 0x100,
 .period_bytes_max = 0x1000,
 .periods_min = 2,
 .periods_max = 64,
};
#endif
static const struct snd_pcm_hardware snd_vortex_playback_hw_spdif = {
 .info =
     (SNDRV_PCM_INFO_MMAP | /* SNDRV_PCM_INFO_RESUME | */
      SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED |
      SNDRV_PCM_INFO_MMAP_VALID),
 .formats =
     SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 |
     SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW |
     SNDRV_PCM_FMTBIT_A_LAW,
 .rates =
     SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
 .rate_min = 32000,
 .rate_max = 48000,
 .channels_min = 1,
 .channels_max = 2,
 .buffer_bytes_max = 0x10000,
 .period_bytes_min = 0x100,
 .period_bytes_max = 0x1000,
 .periods_min = 2,
 .periods_max = 64,
};

#ifndef CHIP_AU8810
static const struct snd_pcm_hardware snd_vortex_playback_hw_wt = {
 .info = (SNDRV_PCM_INFO_MMAP |
   SNDRV_PCM_INFO_INTERLEAVED |
   SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID),
 .formats = SNDRV_PCM_FMTBIT_S16_LE,
 .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000,
 .rate_min = 8000,
 .rate_max = 48000,
 .channels_min = 1,
 .channels_max = 2,
 .buffer_bytes_max = 0x10000,
 .period_bytes_min = 0x0400,
 .period_bytes_max = 0x1000,
 .periods_min = 2,
 .periods_max = 64,
};
#endif
#ifdef CHIP_AU8830
static const unsigned int au8830_channels[3] = {
 1, 2, 4,
};

static const struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
 .count = ARRAY_SIZE(au8830_channels),
 .list = au8830_channels,
 .mask = 0,
};
#endif

static void vortex_notify_pcm_vol_change(struct snd_card *card,
   struct snd_kcontrol *kctl, int activate)
{
 if (activate)
  kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 else
  kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
    SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
}

/* open callback */
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
{
 vortex_t *vortex = snd_pcm_substream_chip(substream);
 struct snd_pcm_runtime *runtime = substream->runtime;
 int err;
 
 /* Force equal size periods */
 err = snd_pcm_hw_constraint_integer(runtime,
         SNDRV_PCM_HW_PARAM_PERIODS);
 if (err < 0)
  return err;
 /* Avoid PAGE_SIZE boundary to fall inside of a period. */
 err = snd_pcm_hw_constraint_pow2(runtime, 0,
      SNDRV_PCM_HW_PARAM_PERIOD_BYTES);
 if (err < 0)
  return err;

 snd_pcm_hw_constraint_step(runtime, 0,
     SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 64);

 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
#ifndef CHIP_AU8820
  if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) {
   runtime->hw = snd_vortex_playback_hw_a3d;
  }
#endif
  if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) {
   runtime->hw = snd_vortex_playback_hw_spdif;
   switch (vortex->spdif_sr) {
   case 32000:
    runtime->hw.rates = SNDRV_PCM_RATE_32000;
    break;
   case 44100:
    runtime->hw.rates = SNDRV_PCM_RATE_44100;
    break;
   case 48000:
    runtime->hw.rates = SNDRV_PCM_RATE_48000;
    break;
   }
  }
  if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB
      || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S)
   runtime->hw = snd_vortex_playback_hw_adb;
#ifdef CHIP_AU8830
  if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
   VORTEX_IS_QUAD(vortex) &&
   VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
   runtime->hw.channels_max = 4;
   snd_pcm_hw_constraint_list(runtime, 0,
    SNDRV_PCM_HW_PARAM_CHANNELS,
    &hw_constraints_au8830_channels);
  }
#endif
  substream->runtime->private_data = NULL;
 }
#ifndef CHIP_AU8810
 else {
  runtime->hw = snd_vortex_playback_hw_wt;
  substream->runtime->private_data = NULL;
 }
#endif
 return 0;
}

/* close callback */
static int snd_vortex_pcm_close(struct snd_pcm_substream *substream)
{
 //vortex_t *chip = snd_pcm_substream_chip(substream);
 stream_t *stream = (stream_t *) substream->runtime->private_data;

 // the hardware-specific codes will be here
 if (stream != NULL) {
  stream->substream = NULL;
  stream->nr_ch = 0;
 }
 substream->runtime->private_data = NULL;
 return 0;
}

/* hw_params callback */
static int
snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
    struct snd_pcm_hw_params *hw_params)
{
 vortex_t *chip = snd_pcm_substream_chip(substream);
 stream_t *stream = (stream_t *) (substream->runtime->private_data);

 /*
   pr_info( "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params),
   params_period_bytes(hw_params), params_channels(hw_params));
 */

 spin_lock_irq(&chip->lock);
 // Make audio routes and config buffer DMA.
 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
  int dma, type = VORTEX_PCM_TYPE(substream->pcm);
  /* Dealloc any routes. */
  if (stream != NULL)
   vortex_adb_allocroute(chip, stream->dma,
           stream->nr_ch, stream->dir,
           stream->type,
           substream->number);
  /* Alloc routes. */
  dma =
      vortex_adb_allocroute(chip, -1,
       params_channels(hw_params),
       substream->stream, type,
       substream->number);
  if (dma < 0) {
   spin_unlock_irq(&chip->lock);
   return dma;
  }
  stream = substream->runtime->private_data = &chip->dma_adb[dma];
  stream->substream = substream;
  /* Setup Buffers. */
  vortex_adbdma_setbuffers(chip, dma,
      params_period_bytes(hw_params),
      params_periods(hw_params));
  if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
   chip->pcm_vol[substream->number].active = 1;
   vortex_notify_pcm_vol_change(chip->card,
    chip->pcm_vol[substream->number].kctl, 1);
  }
 }
#ifndef CHIP_AU8810
 else {
  /* if (stream != NULL)
   vortex_wt_allocroute(chip, substream->number, 0); */

  vortex_wt_allocroute(chip, substream->number,
         params_channels(hw_params));
  stream = substream->runtime->private_data =
      &chip->dma_wt[substream->number];
  stream->dma = substream->number;
  stream->substream = substream;
  vortex_wtdma_setbuffers(chip, substream->number,
     params_period_bytes(hw_params),
     params_periods(hw_params));
 }
#endif
 spin_unlock_irq(&chip->lock);
 return 0;
}

/* hw_free callback */
static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
{
 vortex_t *chip = snd_pcm_substream_chip(substream);
 stream_t *stream = (stream_t *) (substream->runtime->private_data);

 spin_lock_irq(&chip->lock);
 // Delete audio routes.
 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
  if (stream != NULL) {
   if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
    chip->pcm_vol[substream->number].active = 0;
    vortex_notify_pcm_vol_change(chip->card,
     chip->pcm_vol[substream->number].kctl,
     0);
   }
   vortex_adb_allocroute(chip, stream->dma,
           stream->nr_ch, stream->dir,
           stream->type,
           substream->number);
  }
 }
#ifndef CHIP_AU8810
 else {
  if (stream != NULL)
   vortex_wt_allocroute(chip, stream->dma, 0);
 }
#endif
 substream->runtime->private_data = NULL;
 spin_unlock_irq(&chip->lock);

 return 0;
}

/* prepare callback */
static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
{
 vortex_t *chip = snd_pcm_substream_chip(substream);
 struct snd_pcm_runtime *runtime = substream->runtime;
 stream_t *stream = (stream_t *) substream->runtime->private_data;
 int dma = stream->dma, fmt, dir;

 // set up the hardware with the current configuration.
 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  dir = 1;
 else
  dir = 0;
 fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
 spin_lock_irq(&chip->lock);
 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
  vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
    runtime->channels == 1 ? 0 : 1, 0);
  vortex_adbdma_setstartbuffer(chip, dma, 0);
  if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF)
   vortex_adb_setsrc(chip, dma, runtime->rate, dir);
 }
#ifndef CHIP_AU8810
 else {
  vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0);
  // FIXME: Set rate (i guess using vortex_wt_writereg() somehow).
  vortex_wtdma_setstartbuffer(chip, dma, 0);
 }
#endif
 spin_unlock_irq(&chip->lock);
 return 0;
}

/* trigger callback */
static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
 vortex_t *chip = snd_pcm_substream_chip(substream);
 stream_t *stream = (stream_t *) substream->runtime->private_data;
 int dma = stream->dma;

 spin_lock(&chip->lock);
 switch (cmd) {
 case SNDRV_PCM_TRIGGER_START:
  // do something to start the PCM engine
  //printk(KERN_INFO "vortex: start %d\n", dma);
  stream->fifo_enabled = 1;
  if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
   vortex_adbdma_resetup(chip, dma);
   vortex_adbdma_startfifo(chip, dma);
  }
#ifndef CHIP_AU8810
  else {
   dev_info(chip->card->dev, "wt start %d\n", dma);
   vortex_wtdma_startfifo(chip, dma);
  }
#endif
  break;
 case SNDRV_PCM_TRIGGER_STOP:
  // do something to stop the PCM engine
  //printk(KERN_INFO "vortex: stop %d\n", dma);
  stream->fifo_enabled = 0;
  if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
   vortex_adbdma_stopfifo(chip, dma);
#ifndef CHIP_AU8810
  else {
   dev_info(chip->card->dev, "wt stop %d\n", dma);
   vortex_wtdma_stopfifo(chip, dma);
  }
#endif
  break;
 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  //printk(KERN_INFO "vortex: pause %d\n", dma);
  if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
   vortex_adbdma_pausefifo(chip, dma);
#ifndef CHIP_AU8810
  else
   vortex_wtdma_pausefifo(chip, dma);
#endif
  break;
 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  //printk(KERN_INFO "vortex: resume %d\n", dma);
  if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
   vortex_adbdma_resumefifo(chip, dma);
#ifndef CHIP_AU8810
  else
   vortex_wtdma_resumefifo(chip, dma);
#endif
  break;
 default:
  spin_unlock(&chip->lock);
  return -EINVAL;
 }
 spin_unlock(&chip->lock);
 return 0;
}

/* pointer callback */
static snd_pcm_uframes_t snd_vortex_pcm_pointer(struct snd_pcm_substream *substream)
{
 vortex_t *chip = snd_pcm_substream_chip(substream);
 stream_t *stream = (stream_t *) substream->runtime->private_data;
 int dma = stream->dma;
 snd_pcm_uframes_t current_ptr = 0;

 spin_lock(&chip->lock);
 if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT)
  current_ptr = vortex_adbdma_getlinearpos(chip, dma);
#ifndef CHIP_AU8810
 else
  current_ptr = vortex_wtdma_getlinearpos(chip, dma);
#endif
 //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr);
 spin_unlock(&chip->lock);
 current_ptr = bytes_to_frames(substream->runtime, current_ptr);
 if (current_ptr >= substream->runtime->buffer_size)
  current_ptr = 0;
 return current_ptr;
}

/* operators */
static const struct snd_pcm_ops snd_vortex_playback_ops = {
 .open = snd_vortex_pcm_open,
 .close = snd_vortex_pcm_close,
 .hw_params = snd_vortex_pcm_hw_params,
 .hw_free = snd_vortex_pcm_hw_free,
 .prepare = snd_vortex_pcm_prepare,
 .trigger = snd_vortex_pcm_trigger,
 .pointer = snd_vortex_pcm_pointer,
};

/*
*  definitions of capture are omitted here...
*/


static const char * const vortex_pcm_prettyname[VORTEX_PCM_LAST] = {
 CARD_NAME " ADB",
 CARD_NAME " SPDIF",
 CARD_NAME " A3D",
 CARD_NAME " WT",
 CARD_NAME " I2S",
};
static const char * const vortex_pcm_name[VORTEX_PCM_LAST] = {
 "adb",
 "spdif",
 "a3d",
 "wt",
 "i2s",
};

/* SPDIF kcontrol */

static int snd_vortex_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
 uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 uinfo->count = 1;
 return 0;
}

static int snd_vortex_spdif_mask_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
 ucontrol->value.iec958.status[0] = 0xff;
 ucontrol->value.iec958.status[1] = 0xff;
 ucontrol->value.iec958.status[2] = 0xff;
 ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS;
 return 0;
}

static int snd_vortex_spdif_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 ucontrol->value.iec958.status[0] = 0x00;
 ucontrol->value.iec958.status[1] = IEC958_AES1_CON_ORIGINAL|IEC958_AES1_CON_DIGDIGCONV_ID;
 ucontrol->value.iec958.status[2] = 0x00;
 switch (vortex->spdif_sr) {
 case 32000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_32000; break;
 case 44100: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_44100; break;
 case 48000: ucontrol->value.iec958.status[3] = IEC958_AES3_CON_FS_48000; break;
 }
 return 0;
}

static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 int spdif_sr = 48000;
 switch (ucontrol->value.iec958.status[3] & IEC958_AES3_CON_FS) {
 case IEC958_AES3_CON_FS_32000: spdif_sr = 32000; break;
 case IEC958_AES3_CON_FS_44100: spdif_sr = 44100; break;
 case IEC958_AES3_CON_FS_48000: spdif_sr = 48000; break;
 }
 if (spdif_sr == vortex->spdif_sr)
  return 0;
 vortex->spdif_sr = spdif_sr;
 vortex_spdif_init(vortex, vortex->spdif_sr, 1);
 return 1;
}

/* spdif controls */
static const struct snd_kcontrol_new snd_vortex_mixer_spdif[] = {
 {
  .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  .name =  SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
  .info =  snd_vortex_spdif_info,
  .get =  snd_vortex_spdif_get,
  .put =  snd_vortex_spdif_put,
 },
 {
  .access = SNDRV_CTL_ELEM_ACCESS_READ,
  .iface = SNDRV_CTL_ELEM_IFACE_PCM,
  .name =  SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
  .info =  snd_vortex_spdif_info,
  .get =  snd_vortex_spdif_mask_get
 },
};

/* subdevice PCM Volume control */

static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_info *uinfo)
{
 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
 uinfo->value.integer.min = -128;
 uinfo->value.integer.max = 32;
 return 0;
}

static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_value *ucontrol)
{
 int i;
 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 int subdev = kcontrol->id.subdevice;
 struct pcm_vol *p = &vortex->pcm_vol[subdev];
 int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
 for (i = 0; i < max_chn; i++)
  ucontrol->value.integer.value[i] = p->vol[i];
 return 0;
}

static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
    struct snd_ctl_elem_value *ucontrol)
{
 int i;
 int changed = 0;
 int mixin;
 unsigned char vol;
 vortex_t *vortex = snd_kcontrol_chip(kcontrol);
 int subdev = kcontrol->id.subdevice;
 struct pcm_vol *p = &vortex->pcm_vol[subdev];
 int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
 for (i = 0; i < max_chn; i++) {
  if (p->vol[i] != ucontrol->value.integer.value[i]) {
   p->vol[i] = ucontrol->value.integer.value[i];
   if (p->active) {
    switch (vortex->dma_adb[p->dma].nr_ch) {
    case 1:
     mixin = p->mixin[0];
     break;
    case 2:
    default:
     mixin = p->mixin[(i < 2) ? i : (i - 2)];
     break;
    case 4:
     mixin = p->mixin[i];
     break;
    }
    vol = p->vol[i];
    vortex_mix_setinputvolumebyte(vortex,
     vortex->mixplayb[i], mixin, vol);
   }
   changed = 1;
  }
 }
 return changed;
}

static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);

static const struct snd_kcontrol_new snd_vortex_pcm_vol = {
 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
 .name = "PCM Playback Volume",
 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
  SNDRV_CTL_ELEM_ACCESS_INACTIVE,
 .info = snd_vortex_pcm_vol_info,
 .get = snd_vortex_pcm_vol_get,
 .put = snd_vortex_pcm_vol_put,
 .tlv = { .p = vortex_pcm_vol_db_scale },
};

/* create a pcm device */
static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
{
 struct snd_pcm *pcm;
 struct snd_kcontrol *kctl;
 int i;
 int err, nr_capt;

 if (!chip || idx < 0 || idx >= VORTEX_PCM_LAST)
  return -ENODEV;

 /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the 
 * same dma engine. WT uses it own separate dma engine which can't capture. */

 if (idx == VORTEX_PCM_ADB)
  nr_capt = nr;
 else
  nr_capt = 0;
 err = snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr,
     nr_capt, &pcm);
 if (err < 0)
  return err;
 snprintf(pcm->name, sizeof(pcm->name),
  "%s %s", CARD_NAME_SHORT, vortex_pcm_name[idx]);
 chip->pcm[idx] = pcm;
 // This is an evil hack, but it saves a lot of duplicated code.
 VORTEX_PCM_TYPE(pcm) = idx;
 pcm->private_data = chip;
 /* set operators */
 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
   &snd_vortex_playback_ops);
 if (idx == VORTEX_PCM_ADB)
  snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
    &snd_vortex_playback_ops);
 
 /* pre-allocation of Scatter-Gather buffers */
 
 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
           &chip->pci_dev->dev, 0x10000, 0x10000);

 switch (VORTEX_PCM_TYPE(pcm)) {
 case VORTEX_PCM_ADB:
  err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
          snd_pcm_std_chmaps,
          VORTEX_IS_QUAD(chip) ? 4 : 2,
          0, NULL);
  if (err < 0)
   return err;
  err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
          snd_pcm_std_chmaps, 2, 0, NULL);
  if (err < 0)
   return err;
  break;
#ifdef CHIP_AU8830
 case VORTEX_PCM_A3D:
  err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
          snd_pcm_std_chmaps, 1, 0, NULL);
  if (err < 0)
   return err;
  break;
#endif
 }

 if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) {
  for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) {
   kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip);
   if (!kctl)
    return -ENOMEM;
   err = snd_ctl_add(chip->card, kctl);
   if (err < 0)
    return err;
  }
 }
 if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
  for (i = 0; i < NR_PCM; i++) {
   chip->pcm_vol[i].active = 0;
   chip->pcm_vol[i].dma = -1;
   kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
   if (!kctl)
    return -ENOMEM;
   chip->pcm_vol[i].kctl = kctl;
   kctl->id.device = 0;
   kctl->id.subdevice = i;
   err = snd_ctl_add(chip->card, kctl);
   if (err < 0)
    return err;
  }
 }
 return 0;
}

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge