2 * oxfw_stream.c - a part of driver for OXFW970/971 based devices
4 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
5 * Licensed under the terms of the GNU General Public License, version 2.
10 enum control_action
{ CTL_READ
, CTL_WRITE
};
11 enum control_attribute
{
17 static int oxfw_mute_command(struct snd_oxfw
*oxfw
, bool *value
,
18 enum control_action action
)
24 buf
= kmalloc(11, GFP_KERNEL
);
28 if (action
== CTL_READ
) {
29 buf
[0] = 0x01; /* AV/C, STATUS */
30 response_ok
= 0x0c; /* STABLE */
32 buf
[0] = 0x00; /* AV/C, CONTROL */
33 response_ok
= 0x09; /* ACCEPTED */
35 buf
[1] = 0x08; /* audio unit 0 */
36 buf
[2] = 0xb8; /* FUNCTION BLOCK */
37 buf
[3] = 0x81; /* function block type: feature */
38 buf
[4] = oxfw
->device_info
->mute_fb_id
; /* function block ID */
39 buf
[5] = 0x10; /* control attribute: current */
40 buf
[6] = 0x02; /* selector length */
41 buf
[7] = 0x00; /* audio channel number */
42 buf
[8] = 0x01; /* control selector: mute */
43 buf
[9] = 0x01; /* control data length */
44 if (action
== CTL_READ
)
47 buf
[10] = *value
? 0x70 : 0x60;
49 err
= fcp_avc_transaction(oxfw
->unit
, buf
, 11, buf
, 11, 0x3fe);
53 dev_err(&oxfw
->unit
->device
, "short FCP response\n");
57 if (buf
[0] != response_ok
) {
58 dev_err(&oxfw
->unit
->device
, "mute command failed\n");
62 if (action
== CTL_READ
)
63 *value
= buf
[10] == 0x70;
73 static int oxfw_volume_command(struct snd_oxfw
*oxfw
, s16
*value
,
75 enum control_attribute attribute
,
76 enum control_action action
)
82 buf
= kmalloc(12, GFP_KERNEL
);
86 if (action
== CTL_READ
) {
87 buf
[0] = 0x01; /* AV/C, STATUS */
88 response_ok
= 0x0c; /* STABLE */
90 buf
[0] = 0x00; /* AV/C, CONTROL */
91 response_ok
= 0x09; /* ACCEPTED */
93 buf
[1] = 0x08; /* audio unit 0 */
94 buf
[2] = 0xb8; /* FUNCTION BLOCK */
95 buf
[3] = 0x81; /* function block type: feature */
96 buf
[4] = oxfw
->device_info
->volume_fb_id
; /* function block ID */
97 buf
[5] = attribute
; /* control attribute */
98 buf
[6] = 0x02; /* selector length */
99 buf
[7] = channel
; /* audio channel number */
100 buf
[8] = 0x02; /* control selector: volume */
101 buf
[9] = 0x02; /* control data length */
102 if (action
== CTL_READ
) {
106 buf
[10] = *value
>> 8;
110 err
= fcp_avc_transaction(oxfw
->unit
, buf
, 12, buf
, 12, 0x3fe);
114 dev_err(&oxfw
->unit
->device
, "short FCP response\n");
118 if (buf
[0] != response_ok
) {
119 dev_err(&oxfw
->unit
->device
, "volume command failed\n");
123 if (action
== CTL_READ
)
124 *value
= (buf
[10] << 8) | buf
[11];
134 static int oxfw_mute_get(struct snd_kcontrol
*control
,
135 struct snd_ctl_elem_value
*value
)
137 struct snd_oxfw
*oxfw
= control
->private_data
;
139 value
->value
.integer
.value
[0] = !oxfw
->mute
;
144 static int oxfw_mute_put(struct snd_kcontrol
*control
,
145 struct snd_ctl_elem_value
*value
)
147 struct snd_oxfw
*oxfw
= control
->private_data
;
151 mute
= !value
->value
.integer
.value
[0];
153 if (mute
== oxfw
->mute
)
156 err
= oxfw_mute_command(oxfw
, &mute
, CTL_WRITE
);
164 static int oxfw_volume_info(struct snd_kcontrol
*control
,
165 struct snd_ctl_elem_info
*info
)
167 struct snd_oxfw
*oxfw
= control
->private_data
;
169 info
->type
= SNDRV_CTL_ELEM_TYPE_INTEGER
;
170 info
->count
= oxfw
->device_info
->mixer_channels
;
171 info
->value
.integer
.min
= oxfw
->volume_min
;
172 info
->value
.integer
.max
= oxfw
->volume_max
;
177 static const u8 channel_map
[6] = { 0, 1, 4, 5, 2, 3 };
179 static int oxfw_volume_get(struct snd_kcontrol
*control
,
180 struct snd_ctl_elem_value
*value
)
182 struct snd_oxfw
*oxfw
= control
->private_data
;
185 for (i
= 0; i
< oxfw
->device_info
->mixer_channels
; ++i
)
186 value
->value
.integer
.value
[channel_map
[i
]] = oxfw
->volume
[i
];
191 static int oxfw_volume_put(struct snd_kcontrol
*control
,
192 struct snd_ctl_elem_value
*value
)
194 struct snd_oxfw
*oxfw
= control
->private_data
;
195 unsigned int i
, changed_channels
;
196 bool equal_values
= true;
200 for (i
= 0; i
< oxfw
->device_info
->mixer_channels
; ++i
) {
201 if (value
->value
.integer
.value
[i
] < oxfw
->volume_min
||
202 value
->value
.integer
.value
[i
] > oxfw
->volume_max
)
204 if (value
->value
.integer
.value
[i
] !=
205 value
->value
.integer
.value
[0])
206 equal_values
= false;
209 changed_channels
= 0;
210 for (i
= 0; i
< oxfw
->device_info
->mixer_channels
; ++i
)
211 if (value
->value
.integer
.value
[channel_map
[i
]] !=
213 changed_channels
|= 1 << (i
+ 1);
215 if (equal_values
&& changed_channels
!= 0)
216 changed_channels
= 1 << 0;
218 for (i
= 0; i
<= oxfw
->device_info
->mixer_channels
; ++i
) {
219 volume
= value
->value
.integer
.value
[channel_map
[i
? i
- 1 : 0]];
220 if (changed_channels
& (1 << i
)) {
221 err
= oxfw_volume_command(oxfw
, &volume
, i
,
222 CTL_CURRENT
, CTL_WRITE
);
227 oxfw
->volume
[i
- 1] = volume
;
230 return changed_channels
!= 0;
233 int snd_oxfw_create_mixer(struct snd_oxfw
*oxfw
)
235 static const struct snd_kcontrol_new controls
[] = {
237 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
238 .name
= "PCM Playback Switch",
239 .info
= snd_ctl_boolean_mono_info
,
240 .get
= oxfw_mute_get
,
241 .put
= oxfw_mute_put
,
244 .iface
= SNDRV_CTL_ELEM_IFACE_MIXER
,
245 .name
= "PCM Playback Volume",
246 .info
= oxfw_volume_info
,
247 .get
= oxfw_volume_get
,
248 .put
= oxfw_volume_put
,
251 unsigned int i
, first_ch
;
254 err
= oxfw_volume_command(oxfw
, &oxfw
->volume_min
,
255 0, CTL_MIN
, CTL_READ
);
258 err
= oxfw_volume_command(oxfw
, &oxfw
->volume_max
,
259 0, CTL_MAX
, CTL_READ
);
263 err
= oxfw_mute_command(oxfw
, &oxfw
->mute
, CTL_READ
);
267 first_ch
= oxfw
->device_info
->mixer_channels
== 1 ? 0 : 1;
268 for (i
= 0; i
< oxfw
->device_info
->mixer_channels
; ++i
) {
269 err
= oxfw_volume_command(oxfw
, &oxfw
->volume
[i
],
270 first_ch
+ i
, CTL_CURRENT
, CTL_READ
);
275 for (i
= 0; i
< ARRAY_SIZE(controls
); ++i
) {
276 err
= snd_ctl_add(oxfw
->card
,
277 snd_ctl_new1(&controls
[i
], oxfw
));