All of lore.kernel.org
 help / color / mirror / Atom feed
* Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale
       [not found] <ALOGGER1149179663.38@alsa-project.org>
@ 2006-06-10  9:24 ` James Courtier-Dutton
  2006-06-14 14:14   ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: James Courtier-Dutton @ 2006-06-10  9:24 UTC (permalink / raw)
  To: alsa-devel

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@suse.de>
> 
> 
> +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.

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.

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.

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?

James

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale
  2006-06-10  9:24 ` [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale James Courtier-Dutton
@ 2006-06-14 14:14   ` Takashi Iwai
  2006-06-16 10:46     ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2006-06-14 14:14 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

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@suse.de>
> > 
> > 
> > +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;

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale
  2006-06-14 14:14   ` Takashi Iwai
@ 2006-06-16 10:46     ` Takashi Iwai
  2006-06-16 11:00       ` Jaroslav Kysela
  0 siblings, 1 reply; 5+ messages in thread
From: Takashi Iwai @ 2006-06-16 10:46 UTC (permalink / raw)
  To: James Courtier-Dutton; +Cc: alsa-devel

At Wed, 14 Jun 2006 16:14:17 +0200,
I wrote:
> 
> > 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.

After reconsideration, I found it's better to split the ioctl.
It's not nice that the caller has no idea whether the driver actually
reads the value or not.

Still I feel that the implementation of the callback is OK -- keep the
core stuff as small and simple as possible, and let callbacks parse
the user-pointer.


Takashi

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale
  2006-06-16 10:46     ` Takashi Iwai
@ 2006-06-16 11:00       ` Jaroslav Kysela
  2006-06-16 13:22         ` Takashi Iwai
  0 siblings, 1 reply; 5+ messages in thread
From: Jaroslav Kysela @ 2006-06-16 11:00 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, James Courtier-Dutton

On Fri, 16 Jun 2006, Takashi Iwai wrote:

> At Wed, 14 Jun 2006 16:14:17 +0200,
> I wrote:
> > 
> > > 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.
> 
> After reconsideration, I found it's better to split the ioctl.
> It's not nice that the caller has no idea whether the driver actually
> reads the value or not.

Yes, r/w ops should be splited (it's the reason why I used TLV_READ for 
ioctl).

> Still I feel that the implementation of the callback is OK -- keep the
> core stuff as small and simple as possible, and let callbacks parse
> the user-pointer.

I have some cleanup in my tree to reduce memory usage. See bellow. Also, 
while implementing, I realized that it might be worth to add 
SNDRV_CTL_ELEM_ACCESS_TLV_READ and SNDRV_CTL_ELEM_ACCESS_TLV_WRITE flags 
for control elements. Comments?

					Jaroslav

diff -r 08577d0b45ef core/control.c
--- a/core/control.c	Tue Jun 13 12:01:14 2006 +0200
+++ b/core/control.c	Fri Jun 16 12:57:54 2006 +0200
@@ -241,7 +241,7 @@ struct snd_kcontrol *snd_ctl_new1(const 
 	kctl.info = ncontrol->info;
 	kctl.get = ncontrol->get;
 	kctl.put = ncontrol->put;
-	kctl.tlv = ncontrol->tlv;
+	kctl.tlv.p = ncontrol->tlv.p;
 	kctl.private_value = ncontrol->private_value;
 	kctl.private_data = private_data;
 	return snd_ctl_new(&kctl, access);
@@ -1068,8 +1068,9 @@ static int snd_ctl_subscribe_events(stru
 	return 0;
 }
 
-static int snd_ctl_tlv_read(struct snd_card *card,
-                            struct snd_ctl_tlv __user *_tlv)
+static int snd_ctl_tlv_ioctl(struct snd_card *card,
+                             struct snd_ctl_tlv __user *_tlv,
+                             int write_flag)
 {
 	struct snd_ctl_tlv tlv;
 	struct snd_kcontrol *kctl;
@@ -1086,17 +1087,26 @@ 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.p == NULL) {
+		err = -ENXIO;
+		goto __kctl_end;
+	}
+	if (kctl->vd[tlv.numid - kctl->id.numid].access &
+	    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+		err = kctl->tlv.c(kctl, write_flag, tlv.length, _tlv->tlv); 
+	} else {
+	        if (write_flag) {
+	                err = -ENXIO;
+                        goto __kctl_end;
+                }
+		len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
+		if (tlv.length < len) {
+			err = -ENOMEM;
+			goto __kctl_end;
+		}
+		if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
+			err = -EFAULT;
+	}
       __kctl_end:
         up_read(&card->controls_rwsem);
         return err;
@@ -1141,7 +1151,9 @@ static long snd_ctl_ioctl(struct file *f
 	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
 		return snd_ctl_subscribe_events(ctl, ip);
         case SNDRV_CTL_IOCTL_TLV_READ:
-                return snd_ctl_tlv_read(card, argp);
+                return snd_ctl_tlv_ioctl(card, argp, 0);
+        case SNDRV_CTL_IOCTL_TLV_WRITE:
+                return snd_ctl_tlv_ioctl(card, argp, 1);
 	case SNDRV_CTL_IOCTL_POWER:
 		return -ENOPROTOOPT;
 	case SNDRV_CTL_IOCTL_POWER_STATE:
diff -r 08577d0b45ef include/asound.h
--- a/include/asound.h	Tue Jun 13 12:01:14 2006 +0200
+++ b/include/asound.h	Fri Jun 16 12:57:54 2006 +0200
@@ -731,6 +731,7 @@ typedef int __bitwise snd_ctl_elem_iface
 #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually nothing, but may be updated */
 #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
 #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
+#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK	(1<<28)	/* kernel use a TLV callback */ 
 #define SNDRV_CTL_ELEM_ACCESS_USER		(1<<29) /* user space element */
 #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT		(1<<30)	/* indirect access for matrix dimensions in the info structure */
 #define SNDRV_CTL_ELEM_ACCESS_INDIRECT		(1<<31)	/* indirect access for element value in the value structure */
@@ -838,6 +839,7 @@ enum {
 	SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
 	SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
 	SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
+	SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
 	SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
 	SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
 	SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
diff -r 08577d0b45ef include/control.h
--- a/include/control.h	Tue Jun 13 12:01:14 2006 +0200
+++ b/include/control.h	Fri Jun 16 12:57:54 2006 +0200
@@ -30,6 +30,11 @@ 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,
+				    int write_flag,
+				    unsigned int size,
+				    unsigned int __user *tlv);
+
 
 struct snd_kcontrol_new {
 	snd_ctl_elem_iface_t iface;	/* interface identifier */
@@ -42,7 +47,10 @@ struct snd_kcontrol_new {
 	snd_kcontrol_info_t *info;
 	snd_kcontrol_get_t *get;
 	snd_kcontrol_put_t *put;
-	unsigned int *tlv;
+	union {
+        	snd_kcontrol_tlv_rw_t *c;
+        	unsigned int *p;
+        } tlv;
 	unsigned long private_value;
 };
 
@@ -59,7 +67,11 @@ struct snd_kcontrol {
 	snd_kcontrol_info_t *info;
 	snd_kcontrol_get_t *get;
 	snd_kcontrol_put_t *put;
-	unsigned int *tlv;
+	snd_kcontrol_tlv_rw_t *tlv_rw;
+	union {
+	        snd_kcontrol_tlv_rw_t *c;
+        	unsigned int *p;
+        } tlv;
 	unsigned long private_value;
 	void *private_data;
 	void (*private_free)(struct snd_kcontrol *kcontrol);

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project, SUSE Labs

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale
  2006-06-16 11:00       ` Jaroslav Kysela
@ 2006-06-16 13:22         ` Takashi Iwai
  0 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2006-06-16 13:22 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel, James Courtier-Dutton

At Fri, 16 Jun 2006 13:00:57 +0200 (CEST),
Jaroslav Kysela wrote:
> 
> On Fri, 16 Jun 2006, Takashi Iwai wrote:
> 
> > At Wed, 14 Jun 2006 16:14:17 +0200,
> > I wrote:
> > > 
> > > > 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.
> > 
> > After reconsideration, I found it's better to split the ioctl.
> > It's not nice that the caller has no idea whether the driver actually
> > reads the value or not.
> 
> Yes, r/w ops should be splited (it's the reason why I used TLV_READ for 
> ioctl).
> 
> > Still I feel that the implementation of the callback is OK -- keep the
> > core stuff as small and simple as possible, and let callbacks parse
> > the user-pointer.
> 
> I have some cleanup in my tree to reduce memory usage. See bellow. Also, 
> while implementing, I realized that it might be worth to add 
> SNDRV_CTL_ELEM_ACCESS_TLV_READ and SNDRV_CTL_ELEM_ACCESS_TLV_WRITE flags 
> for control elements. Comments?

Looks almost OK but white space problems.

Anyway, let's wait for the consensus.


Takashi

> 
> 					Jaroslav
> 
> diff -r 08577d0b45ef core/control.c
> --- a/core/control.c	Tue Jun 13 12:01:14 2006 +0200
> +++ b/core/control.c	Fri Jun 16 12:57:54 2006 +0200
> @@ -241,7 +241,7 @@ struct snd_kcontrol *snd_ctl_new1(const 
>  	kctl.info = ncontrol->info;
>  	kctl.get = ncontrol->get;
>  	kctl.put = ncontrol->put;
> -	kctl.tlv = ncontrol->tlv;
> +	kctl.tlv.p = ncontrol->tlv.p;
>  	kctl.private_value = ncontrol->private_value;
>  	kctl.private_data = private_data;
>  	return snd_ctl_new(&kctl, access);
> @@ -1068,8 +1068,9 @@ static int snd_ctl_subscribe_events(stru
>  	return 0;
>  }
>  
> -static int snd_ctl_tlv_read(struct snd_card *card,
> -                            struct snd_ctl_tlv __user *_tlv)
> +static int snd_ctl_tlv_ioctl(struct snd_card *card,
> +                             struct snd_ctl_tlv __user *_tlv,
> +                             int write_flag)
>  {
>  	struct snd_ctl_tlv tlv;
>  	struct snd_kcontrol *kctl;
> @@ -1086,17 +1087,26 @@ 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.p == NULL) {
> +		err = -ENXIO;
> +		goto __kctl_end;
> +	}
> +	if (kctl->vd[tlv.numid - kctl->id.numid].access &
> +	    SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
> +		err = kctl->tlv.c(kctl, write_flag, tlv.length, _tlv->tlv); 
> +	} else {
> +	        if (write_flag) {
> +	                err = -ENXIO;
> +                        goto __kctl_end;
> +                }
> +		len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
> +		if (tlv.length < len) {
> +			err = -ENOMEM;
> +			goto __kctl_end;
> +		}
> +		if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
> +			err = -EFAULT;
> +	}
>        __kctl_end:
>          up_read(&card->controls_rwsem);
>          return err;
> @@ -1141,7 +1151,9 @@ static long snd_ctl_ioctl(struct file *f
>  	case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
>  		return snd_ctl_subscribe_events(ctl, ip);
>          case SNDRV_CTL_IOCTL_TLV_READ:
> -                return snd_ctl_tlv_read(card, argp);
> +                return snd_ctl_tlv_ioctl(card, argp, 0);
> +        case SNDRV_CTL_IOCTL_TLV_WRITE:
> +                return snd_ctl_tlv_ioctl(card, argp, 1);
>  	case SNDRV_CTL_IOCTL_POWER:
>  		return -ENOPROTOOPT;
>  	case SNDRV_CTL_IOCTL_POWER_STATE:
> diff -r 08577d0b45ef include/asound.h
> --- a/include/asound.h	Tue Jun 13 12:01:14 2006 +0200
> +++ b/include/asound.h	Fri Jun 16 12:57:54 2006 +0200
> @@ -731,6 +731,7 @@ typedef int __bitwise snd_ctl_elem_iface
>  #define SNDRV_CTL_ELEM_ACCESS_INACTIVE		(1<<8)	/* control does actually nothing, but may be updated */
>  #define SNDRV_CTL_ELEM_ACCESS_LOCK		(1<<9)	/* write lock */
>  #define SNDRV_CTL_ELEM_ACCESS_OWNER		(1<<10)	/* write lock owner */
> +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK	(1<<28)	/* kernel use a TLV callback */ 
>  #define SNDRV_CTL_ELEM_ACCESS_USER		(1<<29) /* user space element */
>  #define SNDRV_CTL_ELEM_ACCESS_DINDIRECT		(1<<30)	/* indirect access for matrix dimensions in the info structure */
>  #define SNDRV_CTL_ELEM_ACCESS_INDIRECT		(1<<31)	/* indirect access for element value in the value structure */
> @@ -838,6 +839,7 @@ enum {
>  	SNDRV_CTL_IOCTL_ELEM_REPLACE = _IOWR('U', 0x18, struct snd_ctl_elem_info),
>  	SNDRV_CTL_IOCTL_ELEM_REMOVE = _IOWR('U', 0x19, struct snd_ctl_elem_id),
>  	SNDRV_CTL_IOCTL_TLV_READ = _IOWR('U', 0x1a, struct snd_ctl_tlv),
> +	SNDRV_CTL_IOCTL_TLV_WRITE = _IOWR('U', 0x1b, struct snd_ctl_tlv),
>  	SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE = _IOWR('U', 0x20, int),
>  	SNDRV_CTL_IOCTL_HWDEP_INFO = _IOR('U', 0x21, struct snd_hwdep_info),
>  	SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE = _IOR('U', 0x30, int),
> diff -r 08577d0b45ef include/control.h
> --- a/include/control.h	Tue Jun 13 12:01:14 2006 +0200
> +++ b/include/control.h	Fri Jun 16 12:57:54 2006 +0200
> @@ -30,6 +30,11 @@ 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,
> +				    int write_flag,
> +				    unsigned int size,
> +				    unsigned int __user *tlv);
> +
>  
>  struct snd_kcontrol_new {
>  	snd_ctl_elem_iface_t iface;	/* interface identifier */
> @@ -42,7 +47,10 @@ struct snd_kcontrol_new {
>  	snd_kcontrol_info_t *info;
>  	snd_kcontrol_get_t *get;
>  	snd_kcontrol_put_t *put;
> -	unsigned int *tlv;
> +	union {
> +        	snd_kcontrol_tlv_rw_t *c;
> +        	unsigned int *p;
> +        } tlv;
>  	unsigned long private_value;
>  };
>  
> @@ -59,7 +67,11 @@ struct snd_kcontrol {
>  	snd_kcontrol_info_t *info;
>  	snd_kcontrol_get_t *get;
>  	snd_kcontrol_put_t *put;
> -	unsigned int *tlv;
> +	snd_kcontrol_tlv_rw_t *tlv_rw;
> +	union {
> +	        snd_kcontrol_tlv_rw_t *c;
> +        	unsigned int *p;
> +        } tlv;
>  	unsigned long private_value;
>  	void *private_data;
>  	void (*private_free)(struct snd_kcontrol *kcontrol);
> 
> -----
> Jaroslav Kysela <perex@suse.cz>
> Linux Kernel Sound Maintainer
> ALSA Project, SUSE Labs
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2006-06-16 13:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <ALOGGER1149179663.38@alsa-project.org>
2006-06-10  9:24 ` [alsa-cvslog] alsa-kernel: Control API - TLV implementation for additional information like dB scale James Courtier-Dutton
2006-06-14 14:14   ` Takashi Iwai
2006-06-16 10:46     ` Takashi Iwai
2006-06-16 11:00       ` Jaroslav Kysela
2006-06-16 13:22         ` Takashi Iwai

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.