[alsa-devel] Regressions on x86(_64) and >128 mixer controls
I have an echo3g (Layla) PCI soundcard on x86_64. alsamixer and alsactl fail with the following:
alsactl: control.c:2976: snd_ctl_elem_value_get_integer: Assertion `idx < ARRAY_SIZE(obj->value.integer.value)' failed.
In question is idx=128, and this "value" array in alsa-lib:
struct snd_ctl_elem_value { struct snd_ctl_elem_id id; /* W: element ID */ unsigned int indirect: 1; /* W: indirect access - obsoleted */ union { union { long value[128]; long *value_ptr; /* obsoleted */ } integer;
At first it appears just to be hitting the fixed limit of 128.
However, this used to work -- and at the time I was using 32-bit kernel and userland on an otherwise similar system (not they are both 64-bit)
Increasing the array size cascades to a new problem which suggests these controls don't actually exist:
./alsactl/alsactl: get_control:258: Cannot read control '2,0,0,PCM Playback Volume,0': Inappropriate ioctl for device
So I investigated the origin of this 256, which is here in linux/sound/pci/echoaudio/echoaudio.c:
static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol); uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->value.integer.min = ECHOGAIN_MINOUT; uinfo->value.integer.max = ECHOGAIN_MAXOUT; uinfo->dimen.d[0] = num_busses_out(chip); /* = 16 */ uinfo->dimen.d[1] = num_busses_in(chip); /* = 16 */ uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1]; /* = 256 */ return 0; }
These values are derived from constants in the source code for this Layla3G device; I can find nothing on this path that would cause variation between a 32-bit and 64-bit kernel -- the code suggests like this value has always been 256 in the kernel, so I can't come up with a reason that it could vary. I don't have enough knowledge of the hardware to know if 256 /is/ the correct value here.
Something which may be related happened for a period when I was using 32-bit userland with 64-bit kernel. This broke a number of tools (incl. echomixer)
Compare alsa-lib/include/alsa/asound.h:
struct snd_ctl_elem_info { struct snd_ctl_elem_id id; /* W: element ID */ snd_ctl_elem_type_t type; /* R: value type - SNDRV_CTL_ELEM_TYPE_* */ unsigned int access; /* R: value access (bitmask) - SNDRV_CTL_ELEM_ACCESS_* */ unsigned int count; /* count of values */ __kernel_pid_t owner; /* owner's PID of this control */ union { struct { long min; /* R: minimum value */ long max; /* R: maximum value */ long step; /* R: step (0 variable) */ } integer;
and notice the use of 'long' in this struct. It has a shadow/equivalent/identical in linux/uapi/sound/asound.h, copied to userland, using:
if (ioctl(hw->fd, SNDRV_CTL_IOCTL_ELEM_INFO, info) < 0) return -errno;
The kernel and userland can have different interpretations of 'long'; do these really not need to be the 'int' type?
Though maybe I am missing something -- surely I am not the only person to have used a 32-bit userland on a 64-bit kernel?
participants (1)
-
Mark Hills