At Thu, 23 Jul 2009 10:39:04 +0200 (CEST), Jaroslav Kysela wrote:
On Thu, 23 Jul 2009, Takashi Iwai wrote:
At Thu, 23 Jul 2009 10:14:27 +0200 (CEST), Jaroslav Kysela wrote:
On Thu, 23 Jul 2009, Wu Fengguang wrote:
Is this with the patched (as is on sound git tree) kernel?
Yes, it's unmodified latest git tree.
What if changing from #if 1 to #if 0?
This makes 8-channel playback work again.
Can we check if we running under VMWare at runtime?
No idea. But, an option to allow to choose manually might be usefl for other broken hardwares that require a similar fallback like VMware, although this doesn't conflict with the automatic detection of vmware.
Yes, maybe a sysfs attribute might be useful.
How about the patch below? This is in sound-unstable tree fix/pcm-hwptr-debug branch.
Takashi
=== From c1506998c994ed10f637d5dde5f4f54ebc1563f3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai tiwai@suse.de Date: Thu, 23 Jul 2009 13:17:50 +0200 Subject: [PATCH] ALSA: pcm - Add sysfs entry to control PCM bogus update filtering
It turned out that the VMware regression fix in the commit 79452f0a28aa5a40522c487b42a5fc423647ad98 introduces another problem for IbexPeak with multi-channels.
This patch adds the new flag and a corresponding sysfs entry to allow to control this behavior dynamically.
Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/pcm.h | 2 ++ sound/core/pcm.c | 34 +++++++++++++++++++++++++++++----- sound/core/pcm_lib.c | 15 +++++++-------- 3 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 2389352..1cd2f18 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -438,6 +438,8 @@ struct snd_pcm { #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) struct snd_pcm_oss oss; #endif + /* misc flags */ + unsigned int filter_bogus_irq:1; };
struct snd_pcm_notify { diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 145931a..15502af 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -942,12 +942,35 @@ static ssize_t show_pcm_class(struct device *dev, return snprintf(buf, PAGE_SIZE, "%s\n", str); }
-static struct device_attribute pcm_attrs = - __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL); +static ssize_t show_pcm_bogus_irq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct snd_pcm *pcm = dev_get_drvdata(dev); + if (!pcm) + return 0; + return sprintf(buf, "%d", pcm->filter_bogus_irq); +} + +static ssize_t store_pcm_bogus_irq(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct snd_pcm *pcm = dev_get_drvdata(dev); + if (!pcm) + return -ENXIO; + pcm->filter_bogus_irq = !!simple_strtoul(buf, NULL, 0); + return count; +} + +static struct device_attribute pcm_attrs[2] = { + __ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL), + __ATTR(pcm_bogus_irq, S_IWUSR|S_IRUGO, + show_pcm_bogus_irq, store_pcm_bogus_irq), +};
static int snd_pcm_dev_register(struct snd_device *device) { - int cidx, err; + int cidx, i, err; struct snd_pcm_substream *substream; struct snd_pcm_notify *notify; char str[16]; @@ -992,8 +1015,9 @@ static int snd_pcm_dev_register(struct snd_device *device) mutex_unlock(®ister_mutex); return err; } - snd_add_device_sysfs_file(devtype, pcm->card, pcm->device, - &pcm_attrs); + for (i = 0; i < ARRAY_SIZE(pcm_attrs); i++) + snd_add_device_sysfs_file(devtype, pcm->card, + pcm->device, &pcm_attrs[i]); for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) snd_pcm_timer_init(substream); } diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 065eaf0..1c1ec4c 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -264,19 +264,18 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) "(stream=%i, pos=%ld, intr_ptr=%ld)\n", substream->stream, (long)pos, (long)hw_ptr_interrupt); -#if 1 - /* simply skipping the hwptr update seems more - * robust in some cases, e.g. on VMware with - * inaccurate timer source - */ - return 0; /* skip this update */ -#else + if (substream->pcm->filter_bogus_irq) { + /* simply skipping the hwptr update seems more + * robust in some cases, e.g. on VMware with + * inaccurate timer source + */ + return 0; /* skip this update */ + } /* rebase to interrupt position */ hw_base = new_hw_ptr = hw_ptr_interrupt; /* align hw_base to buffer_size */ hw_base -= hw_base % runtime->buffer_size; delta = 0; -#endif } else { hw_base += runtime->buffer_size; if (hw_base >= runtime->boundary)