root/sound/firewire/oxfw/oxfw-spkr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. avc_audio_feature_mute
  2. avc_audio_feature_volume
  3. spkr_mute_get
  4. spkr_mute_put
  5. spkr_volume_info
  6. spkr_volume_get
  7. spkr_volume_put
  8. snd_oxfw_add_spkr

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * oxfw-spkr.c - a part of driver for OXFW970/971 based devices
   4  *
   5  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
   6  */
   7 
   8 #include "oxfw.h"
   9 
  10 struct fw_spkr {
  11         bool mute;
  12         s16 volume[6];
  13         s16 volume_min;
  14         s16 volume_max;
  15 
  16         unsigned int mixer_channels;
  17         u8 mute_fb_id;
  18         u8 volume_fb_id;
  19 };
  20 
  21 enum control_action { CTL_READ, CTL_WRITE };
  22 enum control_attribute {
  23         CTL_MIN         = 0x02,
  24         CTL_MAX         = 0x03,
  25         CTL_CURRENT     = 0x10,
  26 };
  27 
  28 static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value,
  29                                   enum control_action action)
  30 {
  31         u8 *buf;
  32         u8 response_ok;
  33         int err;
  34 
  35         buf = kmalloc(11, GFP_KERNEL);
  36         if (!buf)
  37                 return -ENOMEM;
  38 
  39         if (action == CTL_READ) {
  40                 buf[0] = 0x01;          /* AV/C, STATUS */
  41                 response_ok = 0x0c;     /*       STABLE */
  42         } else {
  43                 buf[0] = 0x00;          /* AV/C, CONTROL */
  44                 response_ok = 0x09;     /*       ACCEPTED */
  45         }
  46         buf[1] = 0x08;                  /* audio unit 0 */
  47         buf[2] = 0xb8;                  /* FUNCTION BLOCK */
  48         buf[3] = 0x81;                  /* function block type: feature */
  49         buf[4] = fb_id;                 /* function block ID */
  50         buf[5] = 0x10;                  /* control attribute: current */
  51         buf[6] = 0x02;                  /* selector length */
  52         buf[7] = 0x00;                  /* audio channel number */
  53         buf[8] = 0x01;                  /* control selector: mute */
  54         buf[9] = 0x01;                  /* control data length */
  55         if (action == CTL_READ)
  56                 buf[10] = 0xff;
  57         else
  58                 buf[10] = *value ? 0x70 : 0x60;
  59 
  60         err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe);
  61         if (err < 0)
  62                 goto error;
  63         if (err < 11) {
  64                 dev_err(&unit->device, "short FCP response\n");
  65                 err = -EIO;
  66                 goto error;
  67         }
  68         if (buf[0] != response_ok) {
  69                 dev_err(&unit->device, "mute command failed\n");
  70                 err = -EIO;
  71                 goto error;
  72         }
  73         if (action == CTL_READ)
  74                 *value = buf[10] == 0x70;
  75 
  76         err = 0;
  77 
  78 error:
  79         kfree(buf);
  80 
  81         return err;
  82 }
  83 
  84 static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value,
  85                                     unsigned int channel,
  86                                     enum control_attribute attribute,
  87                                     enum control_action action)
  88 {
  89         u8 *buf;
  90         u8 response_ok;
  91         int err;
  92 
  93         buf = kmalloc(12, GFP_KERNEL);
  94         if (!buf)
  95                 return -ENOMEM;
  96 
  97         if (action == CTL_READ) {
  98                 buf[0] = 0x01;          /* AV/C, STATUS */
  99                 response_ok = 0x0c;     /*       STABLE */
 100         } else {
 101                 buf[0] = 0x00;          /* AV/C, CONTROL */
 102                 response_ok = 0x09;     /*       ACCEPTED */
 103         }
 104         buf[1] = 0x08;                  /* audio unit 0 */
 105         buf[2] = 0xb8;                  /* FUNCTION BLOCK */
 106         buf[3] = 0x81;                  /* function block type: feature */
 107         buf[4] = fb_id;                 /* function block ID */
 108         buf[5] = attribute;             /* control attribute */
 109         buf[6] = 0x02;                  /* selector length */
 110         buf[7] = channel;               /* audio channel number */
 111         buf[8] = 0x02;                  /* control selector: volume */
 112         buf[9] = 0x02;                  /* control data length */
 113         if (action == CTL_READ) {
 114                 buf[10] = 0xff;
 115                 buf[11] = 0xff;
 116         } else {
 117                 buf[10] = *value >> 8;
 118                 buf[11] = *value;
 119         }
 120 
 121         err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe);
 122         if (err < 0)
 123                 goto error;
 124         if (err < 12) {
 125                 dev_err(&unit->device, "short FCP response\n");
 126                 err = -EIO;
 127                 goto error;
 128         }
 129         if (buf[0] != response_ok) {
 130                 dev_err(&unit->device, "volume command failed\n");
 131                 err = -EIO;
 132                 goto error;
 133         }
 134         if (action == CTL_READ)
 135                 *value = (buf[10] << 8) | buf[11];
 136 
 137         err = 0;
 138 
 139 error:
 140         kfree(buf);
 141 
 142         return err;
 143 }
 144 
 145 static int spkr_mute_get(struct snd_kcontrol *control,
 146                          struct snd_ctl_elem_value *value)
 147 {
 148         struct snd_oxfw *oxfw = control->private_data;
 149         struct fw_spkr *spkr = oxfw->spec;
 150 
 151         value->value.integer.value[0] = !spkr->mute;
 152 
 153         return 0;
 154 }
 155 
 156 static int spkr_mute_put(struct snd_kcontrol *control,
 157                          struct snd_ctl_elem_value *value)
 158 {
 159         struct snd_oxfw *oxfw = control->private_data;
 160         struct fw_spkr *spkr = oxfw->spec;
 161         bool mute;
 162         int err;
 163 
 164         mute = !value->value.integer.value[0];
 165 
 166         if (mute == spkr->mute)
 167                 return 0;
 168 
 169         err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute,
 170                                      CTL_WRITE);
 171         if (err < 0)
 172                 return err;
 173         spkr->mute = mute;
 174 
 175         return 1;
 176 }
 177 
 178 static int spkr_volume_info(struct snd_kcontrol *control,
 179                             struct snd_ctl_elem_info *info)
 180 {
 181         struct snd_oxfw *oxfw = control->private_data;
 182         struct fw_spkr *spkr = oxfw->spec;
 183 
 184         info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 185         info->count = spkr->mixer_channels;
 186         info->value.integer.min = spkr->volume_min;
 187         info->value.integer.max = spkr->volume_max;
 188 
 189         return 0;
 190 }
 191 
 192 static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
 193 
 194 static int spkr_volume_get(struct snd_kcontrol *control,
 195                            struct snd_ctl_elem_value *value)
 196 {
 197         struct snd_oxfw *oxfw = control->private_data;
 198         struct fw_spkr *spkr = oxfw->spec;
 199         unsigned int i;
 200 
 201         for (i = 0; i < spkr->mixer_channels; ++i)
 202                 value->value.integer.value[channel_map[i]] = spkr->volume[i];
 203 
 204         return 0;
 205 }
 206 
 207 static int spkr_volume_put(struct snd_kcontrol *control,
 208                            struct snd_ctl_elem_value *value)
 209 {
 210         struct snd_oxfw *oxfw = control->private_data;
 211         struct fw_spkr *spkr = oxfw->spec;
 212         unsigned int i, changed_channels;
 213         bool equal_values = true;
 214         s16 volume;
 215         int err;
 216 
 217         for (i = 0; i < spkr->mixer_channels; ++i) {
 218                 if (value->value.integer.value[i] < spkr->volume_min ||
 219                     value->value.integer.value[i] > spkr->volume_max)
 220                         return -EINVAL;
 221                 if (value->value.integer.value[i] !=
 222                     value->value.integer.value[0])
 223                         equal_values = false;
 224         }
 225 
 226         changed_channels = 0;
 227         for (i = 0; i < spkr->mixer_channels; ++i)
 228                 if (value->value.integer.value[channel_map[i]] !=
 229                                                         spkr->volume[i])
 230                         changed_channels |= 1 << (i + 1);
 231 
 232         if (equal_values && changed_channels != 0)
 233                 changed_channels = 1 << 0;
 234 
 235         for (i = 0; i <= spkr->mixer_channels; ++i) {
 236                 volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
 237                 if (changed_channels & (1 << i)) {
 238                         err = avc_audio_feature_volume(oxfw->unit,
 239                                                   spkr->volume_fb_id, &volume,
 240                                                   i, CTL_CURRENT, CTL_WRITE);
 241                         if (err < 0)
 242                                 return err;
 243                 }
 244                 if (i > 0)
 245                         spkr->volume[i - 1] = volume;
 246         }
 247 
 248         return changed_channels != 0;
 249 }
 250 
 251 int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie)
 252 {
 253         static const struct snd_kcontrol_new controls[] = {
 254                 {
 255                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 256                         .name = "PCM Playback Switch",
 257                         .info = snd_ctl_boolean_mono_info,
 258                         .get = spkr_mute_get,
 259                         .put = spkr_mute_put,
 260                 },
 261                 {
 262                         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 263                         .name = "PCM Playback Volume",
 264                         .info = spkr_volume_info,
 265                         .get = spkr_volume_get,
 266                         .put = spkr_volume_put,
 267                 },
 268         };
 269         struct fw_spkr *spkr;
 270         unsigned int i, first_ch;
 271         int err;
 272 
 273         spkr = devm_kzalloc(&oxfw->card->card_dev, sizeof(struct fw_spkr),
 274                             GFP_KERNEL);
 275         if (!spkr)
 276                 return -ENOMEM;
 277         oxfw->spec = spkr;
 278 
 279         if (is_lacie) {
 280                 spkr->mixer_channels = 1;
 281                 spkr->mute_fb_id = 0x01;
 282                 spkr->volume_fb_id = 0x01;
 283         } else {
 284                 spkr->mixer_channels = 6;
 285                 spkr->mute_fb_id = 0x01;
 286                 spkr->volume_fb_id = 0x02;
 287         }
 288 
 289         err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
 290                                        &spkr->volume_min, 0, CTL_MIN, CTL_READ);
 291         if (err < 0)
 292                 return err;
 293         err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
 294                                        &spkr->volume_max, 0, CTL_MAX, CTL_READ);
 295         if (err < 0)
 296                 return err;
 297 
 298         err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute,
 299                                      CTL_READ);
 300         if (err < 0)
 301                 return err;
 302 
 303         first_ch = spkr->mixer_channels == 1 ? 0 : 1;
 304         for (i = 0; i < spkr->mixer_channels; ++i) {
 305                 err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id,
 306                                                &spkr->volume[i], first_ch + i,
 307                                                CTL_CURRENT, CTL_READ);
 308                 if (err < 0)
 309                         return err;
 310         }
 311 
 312         for (i = 0; i < ARRAY_SIZE(controls); ++i) {
 313                 err = snd_ctl_add(oxfw->card,
 314                                   snd_ctl_new1(&controls[i], oxfw));
 315                 if (err < 0)
 316                         return err;
 317         }
 318 
 319         return 0;
 320 }

/* [<][>][^][v][top][bottom][index][help] */