Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



At Sat, 10 Jun 2006 10:24:26 +0100,
James Courtier-Dutton wrote:
> 
> Jaroslav Kysela wrote:
> > changeset:   4278:d194ae01b0ba9d5614ff29a82f4aacae9edd1212
> > tag:         tip
> > user:        perex
> > date:        Thu Jun  1 18:34:01 2006 +0200
> > files:       core/control.c include/asound.h include/control.h include/tlv.h pci/ca0106/ca0106_mixer.c
> > description:
> > Control API - TLV implementation for additional information like dB scale
> > 
> > This patch implements a TLV mechanism to transfer an additional information
> > like dB scale to the user space. The types might be extended in future.
> > 
> > Acked-by: Takashi Iwai <tiwai@xxxxxxx>
> > 
> > 
> > +struct snd_ctl_tlv {
> > +        unsigned int numid;	/* control element numeric identification */
> > +        unsigned int length;	/* in bytes aligned to 4 */
> > +        unsigned int tlv[0];	/* first TLV */
> > +};
> > +
> 
> > +static int snd_ctl_tlv_read(struct snd_card *card,
> > +                            struct snd_ctl_tlv __user *_tlv)
> > +{
> > +	struct snd_ctl_tlv tlv;
> > +	struct snd_kcontrol *kctl;
> > +	unsigned int len;
> > +	int err = 0;
> > +
> > +	if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
> > +		return -EFAULT;
> > +        if (tlv.length < sizeof(unsigned int) * 3)
> > +                return -EINVAL;
> > +        down_read(&card->controls_rwsem);
> > +        kctl = snd_ctl_find_numid(card, tlv.numid);
> > +        if (kctl == NULL) {
> > +                err = -ENOENT;
> > +                goto __kctl_end;
> > +        }
> > +        if (kctl->tlv == NULL) {
> > +                err = -ENXIO;
> > +                goto __kctl_end;
> > +        }
> > +        len = kctl->tlv[1] + 2 * sizeof(unsigned int);
> > +        if (tlv.length < len) {
> > +                err = -ENOMEM;
> > +                goto __kctl_end;
> > +        }
> > +        if (copy_to_user(_tlv->tlv, kctl->tlv, len))
> > +        	err = -EFAULT;
> > +      __kctl_end:
> > +        up_read(&card->controls_rwsem);
> > +        return err;
> > +}
> 
> I have been away for the last week, so I was not able to comment on this
> commit.

I also didn't expect that the patch was merged so quickly without
testing...

> How do you intend to expand this for requests for anything apart from
> db_scale? For example, how could we get it to return all the current
> "info" (min,max etc.) information instead of the db_scale? Or, are you
> keeping it simple, and make a general request for info from the numid,
> and receive a group of TLVs back for all the different information that
> the numid might contain? I.e. one gets the entire group of information,
> regardless of what is actually needed.

I understand so.  Get TLV composites and parse them in alsa-lib.

> My intention was to place a TLV or multiple TLVs in the request to
> select the information needed, and then receive the TLVs in return.
> 
> For example, audio professionals don't like any volume steps at all.
> They like continuous volume gain adjustment. For example, they request
> +1dB up, the software then gradually increases the actual gain in really
> small steps until a +1dB is reached. This permits totally click free
> volume adjustments. This is all achievable on any sound cards with DSP
> based volume control. (i.e. not cheep hardware based volume control with
> defined steps.). To achieve this, one would pass the raw linear gain
> values from the DSP control (.e.g. 32bit values), and then use some more
> complicated userland (alsa-lib), possibly floating point, conversion
> function to convert it to dB gain levels (e.g.linear to log conversion).
> In this case, one might want the raw linear gain via the
> snd_ctl_tlv_read IOCTL, instead of the stepwise value currently returned
> using the current snd_ca0106_volume_get API. In which case, one would
> need a TLV in the request, to differentiate it from the db_scale request.

Until now, such a hardware-specific thing was supposed to be processed
over hwdep device.  Maybe implementing a new ioctl in control API
might make the alsa-lib code a bit smaller.

> What I am trying to say, is that your "simplification" of the API, has
> resulted in this sort of functionality being excluded, so I would need
> to implement yet another IOCTL to support it! My whole point of using
> the full request/response TLV api, was to not restrict us. I was also
> intending to maybe use the TLVs to set values, as well as just get
> values. For example, another way to implement the "continuous gain"
> feature would be to use the TLV api to set a flag, so that the 32bit
> values are returned via the current snd_ca0106_volume_get(), but only
> for this particular mixer open/close cycle, for backward compatibility
> with the current api.
> 
> Do you prefer separate new IOCTLs for all these features?

We can modify the implementation.  For example, the patch like one
below.  tlv_rw callback is completely free for own implementation.
Each callback is in change of reading/writing the given user-space
pointer arbitrarily.


Takashi


diff -r 08577d0b45ef core/control.c
--- a/core/control.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/core/control.c	Wed Jun 14 16:09:50 2006 +0200
@@ -241,6 +241,7 @@ struct snd_kcontrol *snd_ctl_new1(const 
 	kctl.info = ncontrol->info;
 	kctl.get = ncontrol->get;
 	kctl.put = ncontrol->put;
+	kctl.tlv_rw = ncontrol->tlv_rw;
 	kctl.tlv = ncontrol->tlv;
 	kctl.private_value = ncontrol->private_value;
 	kctl.private_data = private_data;
@@ -1086,17 +1087,21 @@ static int snd_ctl_tlv_read(struct snd_c
                 err = -ENOENT;
                 goto __kctl_end;
         }
-        if (kctl->tlv == NULL) {
-                err = -ENXIO;
-                goto __kctl_end;
-        }
-        len = kctl->tlv[1] + 2 * sizeof(unsigned int);
-        if (tlv.length < len) {
-                err = -ENOMEM;
-                goto __kctl_end;
-        }
-        if (copy_to_user(_tlv->tlv, kctl->tlv, len))
-        	err = -EFAULT;
+	if (kctl->tlv_rw)
+		err = kctl->tlv_rw(kctl, tlv.length, _tlv->tlv); 
+	else {
+		if (kctl->tlv == NULL) {
+			err = -ENXIO;
+			goto __kctl_end;
+		}
+		len = kctl->tlv[1] + 2 * sizeof(unsigned int);
+		if (tlv.length < len) {
+			err = -ENOMEM;
+			goto __kctl_end;
+		}
+		if (copy_to_user(_tlv->tlv, kctl->tlv, len))
+			err = -EFAULT;
+	}
       __kctl_end:
         up_read(&card->controls_rwsem);
         return err;
diff -r 08577d0b45ef include/control.h
--- a/include/control.h	Tue Jun 13 12:01:14 2006 +0200
+++ b/include/control.h	Wed Jun 14 16:09:50 2006 +0200
@@ -30,6 +30,10 @@ typedef int (snd_kcontrol_info_t) (struc
 typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
 typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
 typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
+typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
+				    unsigned int size,
+				    unsigned int __user *tlv);
+
 
 struct snd_kcontrol_new {
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
@@ -42,6 +46,7 @@ struct snd_kcontrol_new {
 	snd_kcontrol_info_t *info;
 	snd_kcontrol_get_t *get;
 	snd_kcontrol_put_t *put;
+	snd_kcontrol_tlv_rw_t *tlv_rw;
 	unsigned int *tlv;
 	unsigned long private_value;
 };
@@ -59,6 +64,7 @@ struct snd_kcontrol {
 	snd_kcontrol_info_t *info;
 	snd_kcontrol_get_t *get;
 	snd_kcontrol_put_t *put;
+	snd_kcontrol_tlv_rw_t *tlv_rw;
 	unsigned int *tlv;
 	unsigned long private_value;
 	void *private_data;


_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux