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 */
|
/* SD_CTL bits */
|
||||||
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
|
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
|
||||||
#define SD_CTL_DMA_START 0x02 /* stream DMA start 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_MASK (0xf << 20)
|
||||||
#define SD_CTL_STREAM_TAG_SHIFT 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 |
|
SNDRV_PCM_INFO_MMAP_VALID |
|
||||||
/* No full-resume yet implemented */
|
/* No full-resume yet implemented */
|
||||||
/* SNDRV_PCM_INFO_RESUME |*/
|
/* SNDRV_PCM_INFO_RESUME |*/
|
||||||
SNDRV_PCM_INFO_PAUSE),
|
SNDRV_PCM_INFO_PAUSE |
|
||||||
|
SNDRV_PCM_INFO_SYNC_START),
|
||||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||||
.rates = SNDRV_PCM_RATE_48000,
|
.rates = SNDRV_PCM_RATE_48000,
|
||||||
.rate_min = 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);
|
spin_unlock_irqrestore(&chip->reg_lock, flags);
|
||||||
|
|
||||||
runtime->private_data = azx_dev;
|
runtime->private_data = azx_dev;
|
||||||
|
snd_pcm_set_sync(substream);
|
||||||
mutex_unlock(&chip->open_mutex);
|
mutex_unlock(&chip->open_mutex);
|
||||||
return 0;
|
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)
|
static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||||
{
|
{
|
||||||
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
|
||||||
struct azx_dev *azx_dev = get_azx_dev(substream);
|
|
||||||
struct azx *chip = apcm->chip;
|
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) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
azx_stream_start(chip, azx_dev);
|
start = 1;
|
||||||
azx_dev->running = 1;
|
|
||||||
break;
|
break;
|
||||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||||
case SNDRV_PCM_TRIGGER_STOP:
|
case SNDRV_PCM_TRIGGER_STOP:
|
||||||
azx_stream_stop(chip, azx_dev);
|
start = 0;
|
||||||
azx_dev->running = 0;
|
|
||||||
break;
|
break;
|
||||||
default:
|
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);
|
spin_unlock(&chip->reg_lock);
|
||||||
if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH ||
|
if (start) {
|
||||||
cmd == SNDRV_PCM_TRIGGER_SUSPEND ||
|
if (nsync == 1)
|
||||||
cmd == SNDRV_PCM_TRIGGER_STOP) {
|
return 0;
|
||||||
int timeout = 5000;
|
/* wait until all FIFOs get ready */
|
||||||
while ((azx_sd_readb(azx_dev, SD_CTL) & SD_CTL_DMA_START) &&
|
for (timeout = 5000; timeout; 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)
|
static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream)
|
||||||
|
Loading…
Reference in New Issue
Block a user