forked from luck/tmp_suning_uos_patched
[ALSA] hda-intel - Add sync support
Addded the support of sync streams to hda-intel driver. Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
f081374b60
commit
850f0e5212
@ -221,6 +221,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
||||
/* SD_CTL bits */
|
||||
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
|
||||
#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
|
||||
#define SD_CTL_STRIPE (3 << 16) /* stripe control */
|
||||
#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
|
||||
#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
|
||||
#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
|
||||
#define SD_CTL_STREAM_TAG_SHIFT 20
|
||||
|
||||
@ -1180,7 +1183,8 @@ static struct snd_pcm_hardware azx_pcm_hw = {
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
/* No full-resume yet implemented */
|
||||
/* SNDRV_PCM_INFO_RESUME |*/
|
||||
SNDRV_PCM_INFO_PAUSE),
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 48000,
|
||||
@ -1242,6 +1246,7 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
||||
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
||||
|
||||
runtime->private_data = azx_dev;
|
||||
snd_pcm_set_sync(substream);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
return 0;
|
||||
}
|
||||
@ -1326,37 +1331,94 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
||||
struct azx *chip = apcm->chip;
|
||||
int err = 0;
|
||||
struct azx_dev *azx_dev;
|
||||
struct snd_pcm_substream *s;
|
||||
int start, nsync = 0, sbits = 0;
|
||||
int nwait, timeout;
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
azx_stream_start(chip, azx_dev);
|
||||
azx_dev->running = 1;
|
||||
start = 1;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
azx_stream_stop(chip, azx_dev);
|
||||
azx_dev->running = 0;
|
||||
start = 0;
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
azx_dev = get_azx_dev(s);
|
||||
sbits |= 1 << azx_dev->index;
|
||||
nsync++;
|
||||
snd_pcm_trigger_done(s, substream);
|
||||
}
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
if (nsync > 1) {
|
||||
/* first, set SYNC bits of corresponding streams */
|
||||
azx_writel(chip, SYNC, azx_readl(chip, SYNC) | sbits);
|
||||
}
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
azx_dev = get_azx_dev(s);
|
||||
if (start)
|
||||
azx_stream_start(chip, azx_dev);
|
||||
else
|
||||
azx_stream_stop(chip, azx_dev);
|
||||
azx_dev->running = start;
|
||||
}
|
||||
spin_unlock(&chip->reg_lock);
|
||||
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
|
||||
cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
|
||||
cmd == SNDRV_PCM_TRIGGER_STOP) {
|
||||
int timeout = 5000;
|
||||
while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&
|
||||
--timeout)
|
||||
;
|
||||
if (start) {
|
||||
if (nsync == 1)
|
||||
return 0;
|
||||
/* wait until all FIFOs get ready */
|
||||
for (timeout = 5000; timeout; timeout--) {
|
||||
nwait = 0;
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
azx_dev = get_azx_dev(s);
|
||||
if (!(azx_sd_readb(azx_dev, SD_STS) &
|
||||
SD_STS_FIFO_READY))
|
||||
nwait++;
|
||||
}
|
||||
if (!nwait)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
} else {
|
||||
/* wait until all RUN bits are cleared */
|
||||
for (timeout = 5000; timeout; timeout--) {
|
||||
nwait = 0;
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
azx_dev = get_azx_dev(s);
|
||||
if (azx_sd_readb(azx_dev, SD_CTL) &
|
||||
SD_CTL_DMA_START)
|
||||
nwait++;
|
||||
}
|
||||
if (!nwait)
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
}
|
||||
return err;
|
||||
if (nsync > 1) {
|
||||
spin_lock(&chip->reg_lock);
|
||||
/* reset SYNC bits */
|
||||
azx_writel(chip, SYNC, azx_readl(chip, SYNC) & ~sbits);
|
||||
spin_unlock(&chip->reg_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
|
Loading…
Reference in New Issue
Block a user