Callbacks

info callback

The info callback is used to get the detailed information of 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 will be:

Example 6-2. Example of info callback

  static int snd_myctl_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 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_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;
  }
            

get callback

This callback is used to read the current value of the control and to return to the 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 is depending on the type of control as well as on 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 is set like

  .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 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 the 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.

Like 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.