/* * set up a BDL entry
*/ staticint setup_bdle(struct snd_pcm_substream *substream, struct lola_stream *str, __le32 **bdlp, int ofs, int size)
{
__le32 *bdl = *bdlp;
while (size > 0) {
dma_addr_t addr; int chunk;
if (str->frags >= LOLA_MAX_BDL_ENTRIES) return -EINVAL;
addr = snd_pcm_sgbuf_get_addr(substream, ofs); /* program the address field of the BDL entry */
bdl[0] = cpu_to_le32((u32)addr);
bdl[1] = cpu_to_le32(upper_32_bits(addr)); /* program the size field of the BDL entry */
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
bdl[2] = cpu_to_le32(chunk); /* program the IOC to enable interrupt * only when the whole fragment is processed
*/
size -= chunk;
bdl[3] = size ? 0 : cpu_to_le32(0x01);
bdl += 4;
str->frags++;
ofs += chunk;
}
*bdlp = bdl; return ofs;
}
/* * set up BDL entries
*/ staticint lola_setup_periods(struct lola *chip, struct lola_pcm *pcm, struct snd_pcm_substream *substream, struct lola_stream *str)
{
__le32 *bdl; int i, ofs, periods, period_bytes;
period_bytes = str->period_bytes;
periods = str->bufsize / period_bytes;
/* program the initial BDL entries */
bdl = (__le32 *)(pcm->bdl->area + LOLA_BDL_ENTRY_SIZE * str->index);
ofs = 0;
str->frags = 0; for (i = 0; i < periods; i++) {
ofs = setup_bdle(substream, str, &bdl, ofs, period_bytes); if (ofs < 0) goto error;
} return 0;
switch (substream->runtime->format) { case SNDRV_PCM_FORMAT_S16_LE:
verb = 0x00000000; break; case SNDRV_PCM_FORMAT_S24_LE:
verb = 0x00000200; break; case SNDRV_PCM_FORMAT_S32_LE:
verb = 0x00000300; break; case SNDRV_PCM_FORMAT_FLOAT_LE:
verb = 0x00001300; break; default: return 0;
}
verb |= substream->runtime->channels; return verb;
}
staticint lola_set_stream_config(struct lola *chip, struct lola_stream *str, int channels)
{ int i, err; unsignedint verb, val;
/* set format info for all channels * (with only one command for the first channel)
*/
err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT,
str->format_verb, 0, &val, NULL); if (err < 0) {
dev_err(chip->card->dev, "Cannot set stream format 0x%x\n",
str->format_verb); return err;
}
switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME:
start = 1; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP:
start = 0; break; default: return -EINVAL;
}
/* * sample correct synchronization is only needed starting several * streams. On stop or if only one stream do as quick as possible
*/
sync_streams = (start && snd_pcm_stream_linked(substream));
tstamp = lola_get_tstamp(chip, !sync_streams);
spin_lock(&chip->reg_lock);
snd_pcm_group_for_each_entry(s, substream) { if (s->pcm->card != substream->pcm->card) continue;
str = lola_get_stream(s); if (start)
lola_stream_start(chip, str, tstamp); else
lola_stream_stop(chip, str, tstamp);
str->running = start;
str->paused = !start;
snd_pcm_trigger_done(s, substream);
}
spin_unlock(&chip->reg_lock); return 0;
}
int lola_create_pcm(struct lola *chip)
{ struct snd_pcm *pcm; int i, err;
for (i = 0; i < 2; i++) {
chip->pcm[i].bdl =
snd_devm_alloc_pages(&chip->pci->dev, SNDRV_DMA_TYPE_DEV,
PAGE_SIZE); if (!chip->pcm[i].bdl) return -ENOMEM;
}
err = snd_pcm_new(chip->card, "Digigram Lola", 0,
chip->pcm[SNDRV_PCM_STREAM_PLAYBACK].num_streams,
chip->pcm[SNDRV_PCM_STREAM_CAPTURE].num_streams,
&pcm); if (err < 0) return err;
strscpy(pcm->name, "Digigram Lola", sizeof(pcm->name));
pcm->private_data = chip; for (i = 0; i < 2; i++) { if (chip->pcm[i].num_streams)
snd_pcm_set_ops(pcm, i, &lola_pcm_ops);
} /* buffer pre-allocation */
snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
&chip->pci->dev,
1024 * 64, 32 * 1024 * 1024); return 0;
}
/*
*/
staticint lola_init_stream(struct lola *chip, struct lola_stream *str, int idx, int nid, int dir)
{ unsignedint val; int err;
str->nid = nid;
str->index = idx;
str->dsd = idx; if (dir == PLAY)
str->dsd += MAX_STREAM_IN_COUNT;
err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); if (err < 0) {
dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid); return err;
} if (dir == PLAY) { /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */ if ((val & 0x00f00dff) != 0x00000010) {
dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n",
val, nid); return -EINVAL;
}
} else { /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) * (bug : ignore bit8: Conn list = 0/1)
*/ if ((val & 0x00f00cff) != 0x00100010) {
dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n",
val, nid); return -EINVAL;
} /* test bit9:DIGITAL and bit12:SRC_PRESENT*/ if ((val & 0x00001200) == 0x00001200)
chip->input_src_caps_mask |= (1 << idx);
}
err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); if (err < 0) {
dev_err(chip->card->dev, "Can't read FORMATS 0x%x\n", nid); return err;
}
val &= 3; if (val == 3)
str->can_float = true; if (!(val & 1)) {
dev_err(chip->card->dev, "Invalid formats 0x%x for 0x%x", val, nid); return -EINVAL;
} return 0;
}
int lola_init_pcm(struct lola *chip, int dir, int *nidp)
{ struct lola_pcm *pcm = &chip->pcm[dir]; int i, nid, err;
nid = *nidp; for (i = 0; i < pcm->num_streams; i++, nid++) {
err = lola_init_stream(chip, &pcm->streams[i], i, nid, dir); if (err < 0) return err;
}
*nidp = nid; return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
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.