[alsa-devel] [PATCH] alsa: lx6464es - initialization fixes
this using this fix, the driver is usable with non-rt kernels. the card initialization is moved from the prepare to the hw_params callback. also the error handling is improved.
Signed-off-by: Tim Blechmann tim@klingt.org --- sound/pci/lx6464es/lx6464es.c | 72 +++++++++++++++++++++-------------------- sound/pci/lx6464es/lx6464es.h | 1 + sound/pci/lx6464es/lx_core.c | 43 +++++++++++++++---------- sound/pci/lx6464es/lx_core.h | 3 +- 4 files changed, 66 insertions(+), 53 deletions(-)
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 1bd7a54..722212e 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -103,16 +103,14 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran);
static int lx_hardware_open(struct lx6464es *chip, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + int channels, snd_pcm_uframes_t period_size) { int err = 0; - struct snd_pcm_runtime *runtime = substream->runtime; - int channels = runtime->channels; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_pcm_uframes_t period_size = runtime->period_size; - - snd_printd(LXP "allocating pipe for %d channels\n", channels); + snd_printk(LXP "allocating pipe for %d channels, %lu period size\n", + channels, period_size); err = lx_pipe_allocate(chip, 0, is_capture, channels); if (err < 0) { snd_printk(KERN_ERR LXP "allocating pipe failed\n"); @@ -130,14 +128,14 @@ static int lx_hardware_open(struct lx6464es *chip, }
static int lx_hardware_start(struct lx6464es *chip, - struct snd_pcm_substream *substream) + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { int err = 0; - struct snd_pcm_runtime *runtime = substream->runtime; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
snd_printd(LXP "setting stream format\n"); - err = lx_stream_set_format(chip, runtime, 0, is_capture); + err = lx_stream_set_format(chip, hw_params, 0, is_capture); if (err < 0) { snd_printk(KERN_ERR LXP "setting stream format failed\n"); return err; @@ -295,13 +293,33 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream return pos; }
+ static int lx_pcm_prepare(struct snd_pcm_substream *substream) { struct lx6464es *chip = snd_pcm_substream_chip(substream); int err = 0; - const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printdd("->lx_pcm_prepare\n"); + snd_printd("->lx_pcm_prepare %d\n", is_capture); + + mutex_lock(&chip->setup_mutex); + + if (chip->board_sample_rate != substream->runtime->rate) { + if (!err) + chip->board_sample_rate = substream->runtime->rate; + } + + mutex_unlock(&chip->setup_mutex); + snd_printd("<-lx_pcm_prepare\n"); + return err; +} + +static int lx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, int is_capture) +{ + struct lx6464es *chip = snd_pcm_substream_chip(substream); + int err = 0; + + snd_printd("->lx_pcm_hw_params\n");
mutex_lock(&chip->setup_mutex);
@@ -322,14 +340,16 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream) }
snd_printd(LXP "opening hardware\n"); - err = lx_hardware_open(chip, substream); + err = lx_hardware_open(chip, substream, + params_channels(hw_params), + params_period_size(hw_params)); if (err < 0) { snd_printk(KERN_ERR LXP "failed to open hardware. " "Error code %d\n", err); goto exit; }
- err = lx_hardware_start(chip, substream); + err = lx_hardware_start(chip, substream, hw_params); if (err < 0) { snd_printk(KERN_ERR LXP "failed to start hardware. " "Error code %d\n", err); @@ -338,26 +358,6 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream)
chip->hardware_running[is_capture] = 1;
- if (chip->board_sample_rate != substream->runtime->rate) { - if (!err) - chip->board_sample_rate = substream->runtime->rate; - } - -exit: - mutex_unlock(&chip->setup_mutex); - return err; -} - -static int lx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params, int is_capture) -{ - struct lx6464es *chip = snd_pcm_substream_chip(substream); - int err = 0; - - snd_printdd("->lx_pcm_hw_params\n"); - - mutex_lock(&chip->setup_mutex); - /* set dma buffer */ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); @@ -367,6 +367,7 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream, else chip->playback_stream.stream = substream;
+exit: mutex_unlock(&chip->setup_mutex); return err; } @@ -389,7 +390,7 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream) int err = 0; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
- snd_printdd("->lx_pcm_hw_free\n"); + snd_printd("->lx_pcm_hw_free\n"); mutex_lock(&chip->setup_mutex);
if (chip->hardware_running[is_capture]) { @@ -477,7 +478,7 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) int err;
snd_printd(LXP "stopping: stopping stream\n"); - err = lx_stream_stop(chip, 0, is_capture); + err = lx_stream_pause(chip, 0, is_capture); if (err < 0) snd_printk(KERN_ERR LXP "couldn't stop stream\n"); else @@ -1005,6 +1006,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, chip->card = card; chip->pci = pci; chip->irq = -1; + chip->hardware_running[0] = chip->hardware_running[1] = 0;
/* initialize synchronization structs */ spin_lock_init(&chip->lock); diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h index aea621e..2a97a21 100644 --- a/sound/pci/lx6464es/lx6464es.h +++ b/sound/pci/lx6464es/lx6464es.h @@ -30,6 +30,7 @@
#include <sound/core.h> #include <sound/pcm.h> +#include <sound/pcm_params.h>
#include "lx_core.h"
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 617f98b..3a9e1dd 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -353,8 +353,11 @@ polling_successful: lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, rmh->stat_len); } - } else + lx_message_dump(rmh); + } else { snd_printk(LXP "rmh error: %08x\n", reg); + dump_stack(); + }
/* clear Reg_CSM_MR */ lx_dsp_reg_write(chip, eReg_CSM, 0); @@ -362,15 +365,11 @@ polling_successful: switch (reg) { case ED_DSP_TIMED_OUT: snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); - return -ETIMEDOUT;
case ED_DSP_CRASHED: snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); - return -EAGAIN; }
- lx_message_dump(rmh); - return reg; }
@@ -532,10 +531,22 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, err = lx_message_send_atomic(chip, &chip->rmh); spin_unlock_irqrestore(&chip->msg_lock, flags);
- if (err != 0) - snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); + if (err == 0) + return 0;
- return err; + switch (err) { + case EB_ALLOCATE_AUDIO_IMPOSSIBLE: + snd_printk(KERN_ERR "lx6464es: could not allocate pipe " + "(EB_ALLOCATE_AUDIO_IMPOSSIBLE)\n"); + break; + + case EB_INVALID_AUDIO: + snd_printk(KERN_ERR "lx6464es: could not allocate pipe " + "(EB_INVALID_AUDIO)\n"); + break; + } + + return -1; }
int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) @@ -781,7 +792,8 @@ int lx_stream_set_state(struct lx6464es *chip, u32 pipe, return err; }
-int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, +int lx_stream_set_format(struct lx6464es *chip, + struct snd_pcm_hw_params *params, u32 pipe, int is_capture) { int err; @@ -789,22 +801,19 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime,
u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe);
- u32 channels = runtime->channels; - - if (runtime->channels != channels) - snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", - runtime->channels, channels); + const u32 channels = params_channels(params); + const snd_pcm_format_t format = params_format(params);
spin_lock_irqsave(&chip->msg_lock, flags); lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM);
chip->rmh.cmd[0] |= pipe_cmd;
- if (runtime->sample_bits == 16) + if (snd_pcm_format_width(format) == 16) /* 16 bit format */ chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET);
- if (snd_pcm_format_little_endian(runtime->format)) + if (snd_pcm_format_little_endian(format)) /* little endian/intel format */ chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET);
@@ -974,7 +983,7 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */
- snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], + snd_printd("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], chip->rmh.cmd[2]);
err = lx_message_send_atomic(chip, &chip->rmh); diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h index 6bd9cbb..378721a 100644 --- a/sound/pci/lx6464es/lx_core.h +++ b/sound/pci/lx6464es/lx_core.h @@ -134,7 +134,8 @@ int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture); int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture);
/* low-level stream handling */ -int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, +int lx_stream_set_format(struct lx6464es *chip, + struct snd_pcm_hw_params *runtime, u32 pipe, int is_capture); int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, int *rstate);
At Mon, 25 Jul 2011 20:34:56 +0200, Tim Blechmann wrote:
this using this fix, the driver is usable with non-rt kernels. the card initialization is moved from the prepare to the hw_params callback.
I don't care much and will accept the change like this (after fixing some issues below), but still wonder why moving to hw_params fixes the issue...
also the error handling is improved.
Signed-off-by: Tim Blechmann tim@klingt.org
sound/pci/lx6464es/lx6464es.c | 72 +++++++++++++++++++++-------------------- sound/pci/lx6464es/lx6464es.h | 1 + sound/pci/lx6464es/lx_core.c | 43 +++++++++++++++---------- sound/pci/lx6464es/lx_core.h | 3 +- 4 files changed, 66 insertions(+), 53 deletions(-)
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 1bd7a54..722212e 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -103,16 +103,14 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran);
static int lx_hardware_open(struct lx6464es *chip,
struct snd_pcm_substream *substream)
struct snd_pcm_substream *substream,
int channels, snd_pcm_uframes_t period_size)
{ int err = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
int channels = runtime->channels; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
snd_pcm_uframes_t period_size = runtime->period_size;
snd_printd(LXP "allocating pipe for %d channels\n", channels);
- snd_printk(LXP "allocating pipe for %d channels, %lu period size\n",
channels, period_size);
Please don't change the debug message to a normal message. This would appear way too likely. Even I think snd_printdd() would be more appropriate there, since snd_printd() is enabled on most distros.
@@ -295,13 +293,33 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream return pos; }
static int lx_pcm_prepare(struct snd_pcm_substream *substream) { struct lx6464es *chip = snd_pcm_substream_chip(substream); int err = 0;
const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
snd_printdd("->lx_pcm_prepare\n");
- snd_printd("->lx_pcm_prepare %d\n", is_capture);
Ditto. I'd suggest to change all this kind of debug prints to snd_printdd(), at least. But this can be done in a different patch.
thanks,
Takashi
this using this fix, the driver is usable with non-rt kernels. the card initialization is moved from the prepare to the hw_params callback.
I don't care much and will accept the change like this (after fixing some issues below), but still wonder why moving to hw_params fixes the issue...
well, i suppose, i am the only user of this driver anyway (at least nobody experienced this issue, which i have been seen on multiple machines). doing some more tests yesteday evening, it seems that this patch fixes the startup issue only in about 90% of all cases. my guess is that it is some kind of timing issue in the communication between driver and microcontroller. most likely because playback and capture devices are started separately.
unfortunately, the error code reported by the uc is not specified in the documentation.
- snd_printd(LXP "allocating pipe for %d channels\n", channels);
- snd_printk(LXP "allocating pipe for %d channels, %lu period size\n",
channels, period_size);
Please don't change the debug message to a normal message. This would appear way too likely. Even I think snd_printdd() would be more appropriate there, since snd_printd() is enabled on most distros.
will prepare a separate patch, when i am back in the studio ...
tim
participants (2)
-
Takashi Iwai
-
Tim Blechmann