1 // SPDX-License-Identifier: GPL-2.0-only
3 * oxfw-spkr.c - a part of driver for OXFW970/971 based devices
5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
16 unsigned int mixer_channels
;
21 enum control_action
{ CTL_READ
, CTL_WRITE
};
22 enum control_attribute
{
28 static int avc_audio_feature_mute(struct fw_unit
*unit
, u8 fb_id
, bool *value
,
29 enum control_action action
)
35 buf
= kmalloc(11, GFP_KERNEL
);
39 if (action
== CTL_READ
) {
40 buf
[0] = 0x01; /* AV/C, STATUS */
41 response_ok
= 0x0c; /* STABLE */
43 buf
[0] = 0x00; /* AV/C, CONTROL */
44 response_ok
= 0x09; /* ACCEPTED */
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
)
58 buf
[10] = *value
? 0x70 : 0x60;
60 err
= fcp_avc_transaction(unit
, buf
, 11, buf
, 11, 0x3fe);
64 dev_err(&unit
->device
, "short FCP response\n");
68 if (buf
[0] != response_ok
) {
69 dev_err(&unit
->device
, "mute command failed\n");
73 if (action
== CTL_READ
)
74 *value
= buf
[10] == 0x70;
84 static int avc_audio_feature_volume(struct fw_unit
*unit
, u8 fb_id
, s16
*value
,
86 enum control_attribute attribute
,
87 enum control_action action
)
93 buf
= kmalloc(12, GFP_KERNEL
);
97 if (action
== CTL_READ
) {
98 buf
[0] = 0x01; /* AV/C, STATUS */
99 response_ok
= 0x0c; /* STABLE */
101 buf
[0] = 0x00; /* AV/C, CONTROL */
102 response_ok
= 0x09; /* ACCEPTED */
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
) {
117 buf
[10] = *value
>> 8;
121 err
= fcp_avc_transaction(unit
, buf
, 12, buf
, 12, 0x3fe);
125 dev_err(&unit
->device
, "short FCP response\n");
129 if (buf
[0] != response_ok
) {
130 dev_err(&unit
->device
, "volume command failed\n");
134 if (action
== CTL_READ
)
135 *value
= (buf
[10] << 8) | buf
[11];
145 static int spkr_mute_get(struct snd_kcontrol
*control
,
146 struct snd_ctl_elem_value
*value
)
148 struct snd_oxfw
*oxfw
= control
->private_data
;
149 struct fw_spkr
*spkr
= oxfw
->spec
;
151 value
->value
.integer
.value
[0] = !spkr
->mute
;
156 static int spkr_mute_put(struct snd_kcontrol
*control
,
157 struct snd_ctl_elem_value
*value
)
159 struct snd_oxfw
*oxfw
= control
->private_data
;
160 struct fw_spkr
*spkr
= oxfw
->spec
;
164 mute
= !value
->value
.integer
.value
[0];
166 if (mute
== spkr
->mute
)
169 err
= avc_audio_feature_mute(oxfw
->unit
, spkr
->mute_fb_id
, &mute
,
178 static int spkr_volume_info(struct snd_kcontrol
*control
,
179 struct snd_ctl_elem_info
*info
)
181 struct snd_oxfw
*oxfw
= control
->private_data
;
182 struct fw_spkr
*spkr
= oxfw
->spec
;
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
;
192 static const u8 channel_map
[6] = { 0, 1, 4, 5, 2, 3 };
194 static int spkr_volume_get(struct snd_kcontrol
*control
,
195 struct snd_ctl_elem_value
*value
)
197 struct snd_oxfw
*oxfw
= control
->private_data
;
198 struct fw_spkr
*spkr
= oxfw
->spec
;
201 for (i
= 0; i
< spkr
->mixer_channels
; ++i
)
202 value
->value
.integer
.value
[channel_map
[i
]] = spkr
->volume
[i
];
207 static int spkr_volume_put(struct snd_kcontrol
*control
,
208 struct snd_ctl_elem_value
*value
)
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;
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
)
221 if (value
->value
.integer
.value
[i
] !=
222 value
->value
.integer
.value
[0])
223 equal_values
= false;
226 changed_channels
= 0;
227 for (i
= 0; i
< spkr
->mixer_channels
; ++i
)
228 if (value
->value
.integer
.value
[channel_map
[i
]] !=
230 changed_channels
|= 1 << (i
+ 1);
232 if (equal_values
&& changed_channels
!= 0)
233 changed_channels
= 1 << 0;
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
);
245 spkr
->volume
[i
- 1] = volume
;
248 return changed_channels
!= 0;
251 int snd_oxfw_add_spkr(struct snd_oxfw
*oxfw
, bool is_lacie
)
253 static const struct snd_kcontrol_new controls
[] = {
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
,
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
,
269 struct fw_spkr
*spkr
;
270 unsigned int i
, first_ch
;
273 spkr
= devm_kzalloc(&oxfw
->card
->card_dev
, sizeof(struct fw_spkr
),
280 spkr
->mixer_channels
= 1;
281 spkr
->mute_fb_id
= 0x01;
282 spkr
->volume_fb_id
= 0x01;
284 spkr
->mixer_channels
= 6;
285 spkr
->mute_fb_id
= 0x01;
286 spkr
->volume_fb_id
= 0x02;
289 err
= avc_audio_feature_volume(oxfw
->unit
, spkr
->volume_fb_id
,
290 &spkr
->volume_min
, 0, CTL_MIN
, CTL_READ
);
293 err
= avc_audio_feature_volume(oxfw
->unit
, spkr
->volume_fb_id
,
294 &spkr
->volume_max
, 0, CTL_MAX
, CTL_READ
);
298 err
= avc_audio_feature_mute(oxfw
->unit
, spkr
->mute_fb_id
, &spkr
->mute
,
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
);
312 for (i
= 0; i
< ARRAY_SIZE(controls
); ++i
) {
313 err
= snd_ctl_add(oxfw
->card
,
314 snd_ctl_new1(&controls
[i
], oxfw
));