Callbacks

info callback
get callback
put callback
Callbacks are not atomic

info callback

The info callback is used to get detailed information on this control. This must store the values of the given struct snd_ctl_elem_info object. For example, for a boolean control with a single element:

Example 6.2. Example of info callback


  static int snd_myctl_mono_info(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_info *uinfo)
  {
          uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
          uinfo->count = 1;
          uinfo->value.integer.min = 0;
          uinfo->value.integer.max = 1;
          return 0;
  }

            


The type field specifies the type of the control. There are BOOLEAN, INTEGER, ENUMERATED, BYTES, IEC958 and INTEGER64. The count field specifies the number of elements in this control. For example, a stereo volume would have count = 2. The value field is a union, and the values stored are depending on the type. The boolean and integer types are identical.

The enumerated type is a bit different from others. You'll need to set the string for the currently given item index.


  static int snd_myctl_enum_info(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_info *uinfo)
  {
          static char *texts[4] = {
                  "First", "Second", "Third", "Fourth"
          };
          uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
          uinfo->count = 1;
          uinfo->value.enumerated.items = 4;
          if (uinfo->value.enumerated.item > 3)
                  uinfo->value.enumerated.item = 3;
          strcpy(uinfo->value.enumerated.name,
                 texts[uinfo->value.enumerated.item]);
          return 0;
  }

            

The above callback can be simplified with a helper function, snd_ctl_enum_info. The final code looks like below. (You can pass ARRAY_SIZE(texts) instead of 4 in the third argument; it's a matter of taste.)


  static int snd_myctl_enum_info(struct snd_kcontrol *kcontrol,
                          struct snd_ctl_elem_info *uinfo)
  {
          static char *texts[4] = {
                  "First", "Second", "Third", "Fourth"
          };
          return snd_ctl_enum_info(uinfo, 1, 4, texts);
  }

            

Some common info callbacks are available for your convenience: snd_ctl_boolean_mono_info() and snd_ctl_boolean_stereo_info(). Obviously, the former is an info callback for a mono channel boolean item, just like snd_myctl_mono_info above, and the latter is for a stereo channel boolean item.

get callback

This callback is used to read the current value of the control and to return to user-space.

For example,

Example 6.3. Example of get callback


  static int snd_myctl_get(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol)
  {
          struct mychip *chip = snd_kcontrol_chip(kcontrol);
          ucontrol->value.integer.value[0] = get_some_value(chip);
          return 0;
  }

            


The value field depends on the type of control as well as on the info callback. For example, the sb driver uses this field to store the register offset, the bit-shift and the bit-mask. The private_value field is set as follows:


  .private_value = reg | (shift << 16) | (mask << 24)

            

and is retrieved in callbacks like


  static int snd_sbmixer_get_single(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_value *ucontrol)
  {
          int reg = kcontrol->private_value & 0xff;
          int shift = (kcontrol->private_value >> 16) & 0xff;
          int mask = (kcontrol->private_value >> 24) & 0xff;
          ....
  }

            

In the get callback, you have to fill all the elements if the control has more than one elements, i.e. count > 1. In the example above, we filled only one element (value.integer.value[0]) since it's assumed as count = 1.

put callback

This callback is used to write a value from user-space.

For example,

Example 6.4. Example of put callback


  static int snd_myctl_put(struct snd_kcontrol *kcontrol,
                           struct snd_ctl_elem_value *ucontrol)
  {
          struct mychip *chip = snd_kcontrol_chip(kcontrol);
          int changed = 0;
          if (chip->current_value !=
               ucontrol->value.integer.value[0]) {
                  change_current_value(chip,
                              ucontrol->value.integer.value[0]);
                  changed = 1;
          }
          return changed;
  }

            


As seen above, you have to return 1 if the value is changed. If the value is not changed, return 0 instead. If any fatal error happens, return a negative error code as usual.

As in the get callback, when the control has more than one elements, all elements must be evaluated in this callback, too.

Callbacks are not atomic

All these three callbacks are basically not atomic.