[alsa-devel] [PATCH 3/3] ALSA: core: set kcontrol's count field correctly

Takashi Iwai tiwai at suse.de
Wed Aug 24 14:05:56 CEST 2011


At Wed, 24 Aug 2011 19:46:13 +0800,
Lu Guanqun wrote:
> 
> On Wed, Aug 24, 2011 at 04:42:05PM +0800, Takashi Iwai wrote:
> > ---
> > diff --git a/include/sound/asound.h b/include/sound/asound.h
> > index 5d6074f..9f5f55d 100644
> > --- a/include/sound/asound.h
> > +++ b/include/sound/asound.h
> > @@ -813,6 +813,33 @@ struct snd_ctl_elem_info {
> >  	unsigned char reserved[64-4*sizeof(unsigned short)];
> >  };
> >  
> > +/* The struct used for ELEM_ADD and ELEM_REPLACE ioctls;
> > + * This is is identical with snd_ctl_elem_info, but just owner field is
> > + * different, keeping the number of elements to be created.
> > + * The unused fields are stripped for simplicity.
> > + */
> > +struct snd_ctl_elem_add_info {
> > +	struct snd_ctl_elem_id id;	/* element ID */
> > +	snd_ctl_elem_type_t type;	/* value type */
> > +	unsigned int access;		/* value access (bitmask) */
> > +	unsigned int count;		/* count of values */
> > +	__kernel_pid_t elem_count;	/* # of elements to create (0=1) */
> > +	union {
> > +		struct {
> > +			long min;		/* R: minimum value */
> > +			long max;		/* R: maximum value */
> > +			long step;		/* R: step (0 variable) */
> > +		} integer;
> > +		struct {
> > +			long long min;		/* R: minimum value */
> > +			long long max;		/* R: maximum value */
> > +			long long step;		/* R: step (0 variable) */
> > +		} integer64;
> > +		unsigned char reserved[128];
> > +	} value;
> > +	unsigned char reserved[64];
> > +};
> > +
> >  struct snd_ctl_elem_value {
> >  	struct snd_ctl_elem_id id;	/* W: element ID */
> >  	unsigned int indirect: 1;	/* W: indirect access - obsoleted */
> > @@ -854,8 +881,8 @@ struct snd_ctl_tlv {
> >  #define SNDRV_CTL_IOCTL_ELEM_LOCK	_IOW('U', 0x14, struct snd_ctl_elem_id)
> >  #define SNDRV_CTL_IOCTL_ELEM_UNLOCK	_IOW('U', 0x15, struct snd_ctl_elem_id)
> >  #define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
> > -#define SNDRV_CTL_IOCTL_ELEM_ADD	_IOWR('U', 0x17, struct snd_ctl_elem_info)
> > -#define SNDRV_CTL_IOCTL_ELEM_REPLACE	_IOWR('U', 0x18, struct snd_ctl_elem_info)
> > +#define SNDRV_CTL_IOCTL_ELEM_ADD	_IOWR('U', 0x17, struct snd_ctl_elem_add_info)
> > +#define SNDRV_CTL_IOCTL_ELEM_REPLACE	_IOWR('U', 0x18, struct snd_ctl_elem_add_info)
> >  #define SNDRV_CTL_IOCTL_ELEM_REMOVE	_IOWR('U', 0x19, struct snd_ctl_elem_id)
> >  #define SNDRV_CTL_IOCTL_TLV_READ	_IOWR('U', 0x1a, struct snd_ctl_tlv)
> >  #define SNDRV_CTL_IOCTL_TLV_WRITE	_IOWR('U', 0x1b, struct snd_ctl_tlv)
> > diff --git a/sound/core/control.c b/sound/core/control.c
> > index dc2a440..15c171d 100644
> > --- a/sound/core/control.c
> > +++ b/sound/core/control.c
> > @@ -1064,7 +1064,7 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
> >  }
> >  
> >  static int snd_ctl_elem_add(struct snd_ctl_file *file,
> > -			    struct snd_ctl_elem_info *info, int replace)
> > +			    struct snd_ctl_elem_add_info *info, int replace)
> >  {
> >  	struct snd_card *card = file->card;
> >  	struct snd_kcontrol kctl, *_kctl;
> > @@ -1099,7 +1099,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
> >  	if (err < 0)
> >  		return err;
> >  	memcpy(&kctl.id, &info->id, sizeof(info->id));
> > -	kctl.count = info->owner ? info->owner : 1;
> > +	kctl.count = info->elem_count ? info->elem_count : 1;
> 
> Hi Takashi,
> 
> I don't how this approach can solve this problem.

There is no problem.  You can't copy the data from ELEM_INFO for
ELEM_ADD/REPLACE.  It was a wrong assumption to reuse the data.
Instead, you had to set up the struct field manually.
That is, the test procedure was simply wrong.

> There's still an
> implicit assumption here that user space application will clear
> info->elem_count to zero before it issues the REPLACE ioctl, right?

Yes, the point is that it's no longer same structure.  So, you can't
copy from the result from ELEM_INFO ioctl any more.  Instead, you need
to set up the struct field manually.

> >  	access |= SNDRV_CTL_ELEM_ACCESS_USER;
> >  	kctl.info = snd_ctl_elem_user_info;
> >  	if (access & SNDRV_CTL_ELEM_ACCESS_READ)
> > @@ -1139,7 +1139,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
> >  	ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
> >  	if (ue == NULL)
> >  		return -ENOMEM;
> > -	ue->info = *info;
> > +	memcpy(&ue->info, info, sizeof(*info));
> 
> Should we add some assertion here checking the size of these two
> structure should be the same?

It could, at most by BUILD_BUG_ON().


thanks,

Takashi


More information about the Alsa-devel mailing list