|
@@ -859,13 +859,18 @@ static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
SD_CTL_DMA_START | SD_INT_MASK);
|
|
|
}
|
|
|
|
|
|
-/* stop a stream */
|
|
|
-static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
+/* stop DMA */
|
|
|
+static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
{
|
|
|
- /* stop DMA */
|
|
|
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
|
|
|
~(SD_CTL_DMA_START | SD_INT_MASK));
|
|
|
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */
|
|
|
+}
|
|
|
+
|
|
|
+/* stop a stream */
|
|
|
+static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
+{
|
|
|
+ azx_stream_clear(chip, azx_dev);
|
|
|
/* disable SIE */
|
|
|
azx_writeb(chip, INTCTL,
|
|
|
azx_readb(chip, INTCTL) & ~(1 << azx_dev->index));
|
|
@@ -1076,8 +1081,7 @@ static int azx_setup_periods(struct azx *chip,
|
|
|
azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
|
|
azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
|
|
|
|
|
- period_bytes = snd_pcm_lib_period_bytes(substream);
|
|
|
- azx_dev->period_bytes = period_bytes;
|
|
|
+ period_bytes = azx_dev->period_bytes;
|
|
|
periods = azx_dev->bufsize / period_bytes;
|
|
|
|
|
|
/* program the initial BDL entries */
|
|
@@ -1124,24 +1128,17 @@ static int azx_setup_periods(struct azx *chip,
|
|
|
error:
|
|
|
snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n",
|
|
|
azx_dev->bufsize, period_bytes);
|
|
|
- /* reset */
|
|
|
- azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
|
|
- azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * set up the SD for streaming
|
|
|
- */
|
|
|
-static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
+/* reset stream */
|
|
|
+static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
{
|
|
|
unsigned char val;
|
|
|
int timeout;
|
|
|
|
|
|
- /* make sure the run bit is zero for SD */
|
|
|
- azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) &
|
|
|
- ~SD_CTL_DMA_START);
|
|
|
- /* reset stream */
|
|
|
+ azx_stream_clear(chip, azx_dev);
|
|
|
+
|
|
|
azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) |
|
|
|
SD_CTL_STREAM_RESET);
|
|
|
udelay(3);
|
|
@@ -1158,7 +1155,15 @@ static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
|
|
|
--timeout)
|
|
|
;
|
|
|
+}
|
|
|
|
|
|
+/*
|
|
|
+ * set up the SD for streaming
|
|
|
+ */
|
|
|
+static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev)
|
|
|
+{
|
|
|
+ /* make sure the run bit is zero for SD */
|
|
|
+ azx_stream_clear(chip, azx_dev);
|
|
|
/* program the stream_tag */
|
|
|
azx_sd_writel(azx_dev, SD_CTL,
|
|
|
(azx_sd_readl(azx_dev, SD_CTL) & ~SD_CTL_STREAM_TAG_MASK)|
|
|
@@ -1403,6 +1408,8 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|
|
runtime->private_data = azx_dev;
|
|
|
snd_pcm_set_sync(substream);
|
|
|
mutex_unlock(&chip->open_mutex);
|
|
|
+
|
|
|
+ azx_stream_reset(chip, azx_dev);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1429,6 +1436,11 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)
|
|
|
static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
|
|
|
struct snd_pcm_hw_params *hw_params)
|
|
|
{
|
|
|
+ struct azx_dev *azx_dev = get_azx_dev(substream);
|
|
|
+
|
|
|
+ azx_dev->bufsize = 0;
|
|
|
+ azx_dev->period_bytes = 0;
|
|
|
+ azx_dev->format_val = 0;
|
|
|
return snd_pcm_lib_malloc_pages(substream,
|
|
|
params_buffer_bytes(hw_params));
|
|
|
}
|
|
@@ -1443,6 +1455,9 @@ static int azx_pcm_hw_free(struct snd_pcm_substream *substream)
|
|
|
azx_sd_writel(azx_dev, SD_BDLPL, 0);
|
|
|
azx_sd_writel(azx_dev, SD_BDLPU, 0);
|
|
|
azx_sd_writel(azx_dev, SD_CTL, 0);
|
|
|
+ azx_dev->bufsize = 0;
|
|
|
+ azx_dev->period_bytes = 0;
|
|
|
+ azx_dev->format_val = 0;
|
|
|
|
|
|
hinfo->ops.cleanup(hinfo, apcm->codec, substream);
|
|
|
|
|
@@ -1456,23 +1471,37 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|
|
struct azx_dev *azx_dev = get_azx_dev(substream);
|
|
|
struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream];
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
|
|
+ unsigned int bufsize, period_bytes, format_val;
|
|
|
+ int err;
|
|
|
|
|
|
- azx_dev->bufsize = snd_pcm_lib_buffer_bytes(substream);
|
|
|
- azx_dev->format_val = snd_hda_calc_stream_format(runtime->rate,
|
|
|
- runtime->channels,
|
|
|
- runtime->format,
|
|
|
- hinfo->maxbps);
|
|
|
- if (!azx_dev->format_val) {
|
|
|
+ format_val = snd_hda_calc_stream_format(runtime->rate,
|
|
|
+ runtime->channels,
|
|
|
+ runtime->format,
|
|
|
+ hinfo->maxbps);
|
|
|
+ if (!format_val) {
|
|
|
snd_printk(KERN_ERR SFX
|
|
|
"invalid format_val, rate=%d, ch=%d, format=%d\n",
|
|
|
runtime->rate, runtime->channels, runtime->format);
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ bufsize = snd_pcm_lib_buffer_bytes(substream);
|
|
|
+ period_bytes = snd_pcm_lib_period_bytes(substream);
|
|
|
+
|
|
|
snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n",
|
|
|
- azx_dev->bufsize, azx_dev->format_val);
|
|
|
- if (azx_setup_periods(chip, substream, azx_dev) < 0)
|
|
|
- return -EINVAL;
|
|
|
+ bufsize, format_val);
|
|
|
+
|
|
|
+ if (bufsize != azx_dev->bufsize ||
|
|
|
+ period_bytes != azx_dev->period_bytes ||
|
|
|
+ format_val != azx_dev->format_val) {
|
|
|
+ azx_dev->bufsize = bufsize;
|
|
|
+ azx_dev->period_bytes = period_bytes;
|
|
|
+ azx_dev->format_val = format_val;
|
|
|
+ err = azx_setup_periods(chip, substream, azx_dev);
|
|
|
+ if (err < 0)
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
azx_setup_controller(chip, azx_dev);
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
|