[alsa-devel] [PATCH] Sound: MSM soc : imported alsa for the MSM from codeaurora

GNUtoo GNUtoo at no-log.org
Sun Nov 15 21:06:40 CET 2009


On Fri, 2009-11-13 at 14:50 +0000, Mark Brown wrote:
> On Sun, Nov 08, 2009 at 11:46:10PM +0100, Denis 'GNUtoo' Carikli wrote:
> 
> Please do try to rememeber to CC maintainers on patches...
> 
> I've read some, but not all of this since I really can't follow how the
> code is supposed to be constructed.  At the minute there doesn't feel
> like there's enough abstraction between the various parts of the code,
> with lots of things cropping up in unexpected places and making it
> harder to follow.
> 
> It would probably be useful to refactor things so that you've got a
> support layer for the DSP that deals with any resource sharing issues
> and then build more standard-looking CODEC, DAI and DMA drivers (the DAI
> driver would probably be largely empty, I guess) with a machine driver
> gluing them together.
> 
> > it still has serious runtime problems such as:
> > *Can produce kernel oops under theses conditions:
> >  start alsamixer and if the second bar is on 0 or 4,
> >  so it can play music with aplay,then increase the routing alsamixer bar
> >  to the max.
> >  Then decrease the routing bar to 4 or less
> 
> What are "the second bar" and "routing bar"?  Remember, most of the
> people reading your mail will never have seen your system running.
> 
> > +config SND_MSM_DAI_SOC
> > +	tristate "SoC CPU/CODEC DAI for the MSM chip"
> > +	depends on SND_MSM_SOC || SND_QSD_SOC
> > +	help
> > +	 To add support for ALSA PCM driver for MSM board.
> 
> No need to make this one uer visible.
> 
> > +
> > +config SND_MSM_SOC_MSM7K
> > +        tristate "SoC Audio support for MSM7K"
> > +        depends on SND_MSM_SOC
> 
> Or this.  I know some architectures do this but we should probably just
> move them to visibly select only boards.
> 
> > +	codec->name = "MSM-CARD";
> 
> Probably something like "MSM7xxx internal CODEC" or similar.
> 
> > +static int __init msm_dai_init(void)
> > +{
> > +	return snd_soc_register_dais(msm_dais, ARRAY_SIZE(msm_dais));
> > +}
> > +
> > +static void __exit msm_dai_exit(void)
> > +{
> > +	snd_soc_unregister_dais(msm_dais, ARRAY_SIZE(msm_dais));
> > +}
> 
> Your DAIs ought to be registered as platform devices under arch/arm,
> probe as normal platform devices and then register the DAIs when these
> probe.
> 
> > +#define audio_send_queue_recbs(prtd, cmd, len) \
> > +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecBitStreamQueue, cmd, len)
> > +#define audio_send_queue_rec(prtd, cmd, len) \
> > +	msm_adsp_write(prtd->audrec, QDSP_uPAudRecCmdQueue, cmd, len)
> 
> Inline functions, please.
> 
> > +int msm_audio_volume_update(unsigned id,
> > +				int volume, int pan)
> > +{
> > +	unsigned vol_raw;
> > +
> > +	vol_raw = compute_db_raw(volume);
> > +	printk(KERN_INFO "volume: %8x vol_raw: %8x \n", volume, vol_raw);
> > +	return audpp_set_volume_and_pan(id, vol_raw, pan);
> > +}
> > +EXPORT_SYMBOL(msm_audio_volume_update);
> 
> Hrm?
> 
> > +			unsigned id = msg[2];
> > +			unsigned idx = msg[3] - 1;
> > +			if (id != AUDPP_MSG_HOSTPCM_ID_ARM_RX) {
> > +				printk(KERN_ERR "bogus id\n");
> > +				break;
> 
> With stuff like this displaying what the bogus IDs are would be useful.
> 
> > +			/* Update with actual sent buffer size */
> > +			if (prtd->out[idx].used != BUF_INVALID_LEN)
> > +				prtd->pcm_irq_pos += prtd->out[idx].used;
> > +
> > +			if (prtd->pcm_irq_pos > prtd->pcm_size)
> > +				prtd->pcm_irq_pos = prtd->pcm_count;
> 
> This looks suspicious - it looks like what's going on is that you're
> getting a notification from the DSP that it has consumed a data buffer
> but this might go out of bounds and get clamped.
> 
> > +			if (prtd->ops->playback)
> > +				prtd->ops->playback(prtd);
> > +
> > +			spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> > +			if (prtd->running) {
> > +				prtd->out[idx].used = 0;
> > +				frame = prtd->out + prtd->out_tail;
> > +				if (frame->used) {
> > +					audio_dsp_send_buffer(prtd,
> > +							      prtd->out_tail,
> > +							      frame->used);
> > +					prtd->out_tail ^= 1;
> 
> I've got a feeling that this code would be a lot easier to follow if
> you used a linked list of buffers.  You could statically allocate all the
> buffers still, but it'd make it much more explicit what was going on if
> you had a list of buffers queued for transmission to the DSP and a list
> of free buffers.
> 
> Given what it looks like this is doing I'd really expect
> snd_pcm_period_elapsed to be called directly from here - the playback
> and capture code paths appear to be completely separate and the
> indirections you're using appear not to be needed.  I'd also expect
> it to be called after you've finished updating the buffers rather than
> before, especially given that you appear to call it outside the lock on
> buffer updates.
> 
> > +				} else {
> > +					prtd->out_needed++;
> > +				}
> > +				wake_up(&the_locks.write_wait);
> 
> Why this?
> 
> > +	if (prtd->dir == SNDRV_PCM_STREAM_PLAYBACK) {
> > +		prtd->out_buffer_size = PLAYBACK_DMASZ;
> > +		prtd->out_sample_rate = 44100;
> > +		prtd->out_channel_mode = AUDPP_CMD_PCM_INTF_STEREO_V;
> > +		prtd->out_weight = 100;
> 
> You're not setting any 
> 
> > +int alsa_audio_configure(struct msm_audio *prtd)
> > +{
> > +	struct audmgr_config cfg;
> > +	int rc;
> > +
> > +	if (prtd->enabled)
> > +		return 0;
> > +
> > +	/* refuse to start if we're not ready with first buffer */
> > +	if (!prtd->out[0].used)
> > +		return -EIO;
> > +
> > +	cfg.tx_rate = 0;
> > +	cfg.rx_rate = RPC_AUD_DEF_SAMPLE_RATE_48000;
> 
> Your code appears to hard code both 44.1k and 48k inconsistently.
> 
> > +		audmgr_disable(&prtd->audmgr);
> > +		return -ENODEV;
> > +	}
> > +
> > +	prtd->enabled = 1;
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(alsa_audio_configure);
> 
> This looks extremely suspect...
> 
> > +ssize_t alsa_send_buffer(struct msm_audio *prtd, const char __user *buf,
> > +			  size_t count, loff_t *pos)
> > +{
> > +	unsigned long flag;
> > +	const char __user *start = buf;
> > +	struct buffer *frame;
> > +	size_t xfer;
> > +	int rc = 0;
> > +
> > +	mutex_lock(&the_locks.write_lock);
> > +	while (count > 0) {
> > +		frame = prtd->out + prtd->out_head;
> > +		rc = wait_event_interruptible(the_locks.write_wait,
> > +					      (frame->used == 0)
> > +					      || (prtd->stopped));
> > +		if (rc < 0)
> > +			break;
> > +		if (prtd->stopped) {
> > +			rc = -EBUSY;
> > +			break;
> > +		}
> > +		xfer = count > frame->size ? frame->size : count;
> > +		if (copy_from_user(frame->data, buf, xfer)) {
> > +			rc = -EFAULT;
> > +			break;
> > +		}
> > +		frame->used = xfer;
> > +		prtd->out_head ^= 1;
> > +		count -= xfer;
> > +		buf += xfer;
> > +
> > +		spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
> > +		frame = prtd->out + prtd->out_tail;
> > +		if (frame->used && prtd->out_needed) {
> > +			audio_dsp_send_buffer(prtd, prtd->out_tail,
> > +					      frame->used);
> > +			prtd->out_tail ^= 1;
> 
> These ^s really don't help legibility.
> 
> > +			prtd->out_needed--;
> > +		}
> > +		spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
> > +	}
> > +	mutex_unlock(&the_locks.write_lock);
> > +	if (buf > start)
> > +		return buf - start;
> > +	return rc;
> > +}
> > +EXPORT_SYMBOL(alsa_send_buffer);
> 
> ...as does this.  There should be no need to export all this stuff, and
> if you are exporting it it ought to be _GPL since all the ASoC APIs are
> _GPL.
> 
> I'd also really like to see some explanation of what the locking scheme
> is supposed to be - I can't quite follow what's supposed to be protected
> against what and when but I suspect there's cases where either read or
> write lock is taken and the_locks.lock is really needed.
> 
> > +EXPORT_SYMBOL(alsa_audio_disable);
> 
> > +#include <../arch/arm/mach-msm/qdsp5/adsp.h>
> > +#include <../arch/arm/mach-msm/qdsp5/audmgr.h>
> 
> Put these in an include directory.
> 
> > +#define FRAME_NUM               (8)
> > +#define FRAME_SIZE              (2052 * 2)
> > +#define MONO_DATA_SIZE          (2048)
> > +#define STEREO_DATA_SIZE        (MONO_DATA_SIZE * 2)
> > +#define CAPTURE_DMASZ           (FRAME_SIZE * FRAME_NUM)
> > +
> > +#define BUFSZ			(960 * 5)
> > +#define PLAYBACK_DMASZ 		(BUFSZ * 2)
> 
> All this stuff needs namespacing.
> 
> > +/* Support unconventional sample rates 12000, 24000 as well */
> > +#define USE_RATE                \
> > +			(SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
> 
> Your code doesn't appear to actually cope with all these rates.  Also,
> these ought to be pushed down into the drivers rather than exported in
> the header file - there's no need for other drivers to see them.
> 
> > +static int snd_msm_volume_put(struct snd_kcontrol *kcontrol,
> > +				struct snd_ctl_elem_value *ucontrol)
> > +{
> > +	int change;
> > +	int volume;
> > +
> > +	volume = ucontrol->value.integer.value[0];
> > +	spin_lock_irq(&the_locks.mixer_lock);
> > +	change = (msm_vol_ctl.volume != volume);
> > +	if (change) {
> > +		msm_vol_ctl.update = 1;
> > +		msm_vol_ctl.volume = volume;
> > +	}
> > +	spin_unlock_irq(&the_locks.mixer_lock);
> 
> This doesn't actually appear to do anything to propagate the changes to
> the DSP?
> 
> > +static struct snd_kcontrol_new snd_msm_controls[] = {
> > +	MSM_EXT_TLV("PCM Playback Volume", 0, snd_msm_volume_info, \
> > +	snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
> > +	MSM_EXT("device", 1, snd_msm_device_info, snd_msm_device_get, \
> > +						 snd_msm_device_put, 0),
> > +};
> 
> I have no idea what "device" is supposed to be.
> 
> > +static struct snd_soc_dai_link msm_dai = {
> > +	.name = "ASOC",
> > +	.stream_name = "ASOC",
> > +	.codec_dai = &msm_dais[0],
> > +	.cpu_dai = &msm_dais[1],
> > +	.init	= msm_soc_dai_init,
> > +};
> 
> Please pick some human readable names describing the setup (eg, "MSM7k
> internal CODEC").

Thanks a lot!!!
I'll try to fix most of the problems and resend a patch,I'll also
continue the debugging...which will take some time....

About the debugging:
*I noticed that if I change the .buffer_bytes_max to 4800 aplay doesn't
work anymore...I'll try to find the good values...
*I also noticed that aplay doesn't use the SNDRV_PCM_IOCTL_STATUS which
would explain why aplay works and not mplayer... so I'll try to fix that
too...

Denis.




More information about the Alsa-devel mailing list