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