Commit 8d48c016 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: x86: Allow single period PCM operation

This is an implementation of PCM streaming with only 1 period.
Since the hardware requires the refresh of BDs after each BD
processing finishes, we'd need at least two BDs.  The trick is that
both BDs point to the same content: the address of the PCM buffer
head, and the whole buffer size.  Then it loops over to the whole
buffer again after it finished once.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a9ebdd0e
...@@ -822,6 +822,11 @@ static int had_prog_n(u32 aud_samp_freq, u32 *n_param, ...@@ -822,6 +822,11 @@ static int had_prog_n(u32 aud_samp_freq, u32 *n_param,
* *
* For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that
* the hardware skips those BDs in the loop. * the hardware skips those BDs in the loop.
*
* An exceptional setup is the case with nperiods=1. Since we have to update
* BDs after finishing one BD processing, we'd need at least two BDs, where
* both BDs point to the same content, the same address, the same size of the
* whole PCM buffer.
*/ */
#define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH) #define AUD_BUF_ADDR(x) (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH)
...@@ -864,6 +869,8 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream, ...@@ -864,6 +869,8 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream,
num_periods = runtime->periods; num_periods = runtime->periods;
intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS); intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS);
/* set the minimum 2 BDs for num_periods=1 */
intelhaddata->num_bds = max(intelhaddata->num_bds, 2U);
intelhaddata->period_bytes = intelhaddata->period_bytes =
frames_to_bytes(runtime, runtime->period_size); frames_to_bytes(runtime, runtime->period_size);
WARN_ON(intelhaddata->period_bytes & 0x3f); WARN_ON(intelhaddata->period_bytes & 0x3f);
...@@ -873,7 +880,7 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream, ...@@ -873,7 +880,7 @@ static void had_init_ringbuf(struct snd_pcm_substream *substream,
intelhaddata->pcmbuf_filled = 0; intelhaddata->pcmbuf_filled = 0;
for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) { for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) {
if (i < num_periods) if (i < intelhaddata->num_bds)
had_prog_bd(substream, intelhaddata); had_prog_bd(substream, intelhaddata);
else /* invalidate the rest */ else /* invalidate the rest */
had_invalidate_bd(intelhaddata, i); had_invalidate_bd(intelhaddata, i);
...@@ -1255,7 +1262,10 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream) ...@@ -1255,7 +1262,10 @@ static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
len = had_process_ringbuf(substream, intelhaddata); len = had_process_ringbuf(substream, intelhaddata);
if (len < 0) if (len < 0)
return SNDRV_PCM_POS_XRUN; return SNDRV_PCM_POS_XRUN;
return bytes_to_frames(substream->runtime, len); len = bytes_to_frames(substream->runtime, len);
/* wrapping may happen when periods=1 */
len %= substream->runtime->buffer_size;
return len;
} }
/* /*
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#define HAD_MAX_BUFFER ((1024 * 1024 - 1) & ~0x3f) #define HAD_MAX_BUFFER ((1024 * 1024 - 1) & ~0x3f)
#define HAD_DEFAULT_BUFFER (600 * 1024) /* default prealloc size */ #define HAD_DEFAULT_BUFFER (600 * 1024) /* default prealloc size */
#define HAD_MAX_PERIODS 256 /* arbitrary, but should suffice */ #define HAD_MAX_PERIODS 256 /* arbitrary, but should suffice */
#define HAD_MIN_PERIODS 2 #define HAD_MIN_PERIODS 1
#define HAD_MAX_PERIOD_BYTES ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f) #define HAD_MAX_PERIOD_BYTES ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f)
#define HAD_MIN_PERIOD_BYTES 1024 /* might be smaller */ #define HAD_MIN_PERIOD_BYTES 1024 /* might be smaller */
#define HAD_FIFO_SIZE 0 /* fifo not being used */ #define HAD_FIFO_SIZE 0 /* fifo not being used */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment