diff options
author | Torsten Schenk <torsten.schenk@zoho.com> | 2011-04-04 05:50:53 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-04-04 06:26:21 -0400 |
commit | 2475b0d407614ea5a41b8325d45c614d94087088 (patch) | |
tree | 397aa0eb6ae0f7220992fcd98b6dd86e8271be76 /sound/usb/6fire/control.c | |
parent | b84610b95f7e7bcd1cd9ecf3e8506a59e9f557fd (diff) |
ALSA: 6fire - Add support of digital-thru mixer
Digital Thru mixer element added (device can act as converter optical<->coax)
Signed-off-by: Torsten Schenk <torsten.schenk@zoho.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb/6fire/control.c')
-rw-r--r-- | sound/usb/6fire/control.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index 248463511186..ac828eff1a63 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c | |||
@@ -65,6 +65,15 @@ init_data[] = { | |||
65 | { 0 } /* TERMINATING ENTRY */ | 65 | { 0 } /* TERMINATING ENTRY */ |
66 | }; | 66 | }; |
67 | 67 | ||
68 | static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; | ||
69 | /* values to write to soundcard register for all samplerates */ | ||
70 | static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; | ||
71 | static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; | ||
72 | |||
73 | enum { | ||
74 | DIGITAL_THRU_ONLY_SAMPLERATE = 3 | ||
75 | }; | ||
76 | |||
68 | static void usb6fire_control_master_vol_update(struct control_runtime *rt) | 77 | static void usb6fire_control_master_vol_update(struct control_runtime *rt) |
69 | { | 78 | { |
70 | struct comm_runtime *comm_rt = rt->chip->comm; | 79 | struct comm_runtime *comm_rt = rt->chip->comm; |
@@ -95,6 +104,67 @@ static void usb6fire_control_opt_coax_update(struct control_runtime *rt) | |||
95 | } | 104 | } |
96 | } | 105 | } |
97 | 106 | ||
107 | static int usb6fire_control_set_rate(struct control_runtime *rt, int rate) | ||
108 | { | ||
109 | int ret; | ||
110 | struct usb_device *device = rt->chip->dev; | ||
111 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
112 | |||
113 | if (rate < 0 || rate >= CONTROL_N_RATES) | ||
114 | return -EINVAL; | ||
115 | |||
116 | ret = usb_set_interface(device, 1, rates_altsetting[rate]); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | /* set soundcard clock */ | ||
121 | ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rate], | ||
122 | rates_6fire_vh[rate]); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int usb6fire_control_set_channels( | ||
130 | struct control_runtime *rt, int n_analog_out, | ||
131 | int n_analog_in, bool spdif_out, bool spdif_in) | ||
132 | { | ||
133 | int ret; | ||
134 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
135 | |||
136 | /* enable analog inputs and outputs | ||
137 | * (one bit per stereo-channel) */ | ||
138 | ret = comm_rt->write16(comm_rt, 0x02, 0x02, | ||
139 | (1 << (n_analog_out / 2)) - 1, | ||
140 | (1 << (n_analog_in / 2)) - 1); | ||
141 | if (ret < 0) | ||
142 | return ret; | ||
143 | |||
144 | /* disable digital inputs and outputs */ | ||
145 | /* TODO: use spdif_x to enable/disable digital channels */ | ||
146 | ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00); | ||
147 | if (ret < 0) | ||
148 | return ret; | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int usb6fire_control_streaming_update(struct control_runtime *rt) | ||
154 | { | ||
155 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
156 | |||
157 | if (comm_rt) { | ||
158 | if (!rt->usb_streaming && rt->digital_thru_switch) | ||
159 | usb6fire_control_set_rate(rt, | ||
160 | DIGITAL_THRU_ONLY_SAMPLERATE); | ||
161 | return comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, | ||
162 | (rt->usb_streaming ? 0x01 : 0x00) | | ||
163 | (rt->digital_thru_switch ? 0x08 : 0x00)); | ||
164 | } | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
98 | static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, | 168 | static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, |
99 | struct snd_ctl_elem_info *uinfo) | 169 | struct snd_ctl_elem_info *uinfo) |
100 | { | 170 | { |
@@ -195,6 +265,28 @@ static int usb6fire_control_opt_coax_get(struct snd_kcontrol *kcontrol, | |||
195 | return 0; | 265 | return 0; |
196 | } | 266 | } |
197 | 267 | ||
268 | static int usb6fire_control_digital_thru_put(struct snd_kcontrol *kcontrol, | ||
269 | struct snd_ctl_elem_value *ucontrol) | ||
270 | { | ||
271 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
272 | int changed = 0; | ||
273 | |||
274 | if (rt->digital_thru_switch != ucontrol->value.integer.value[0]) { | ||
275 | rt->digital_thru_switch = ucontrol->value.integer.value[0]; | ||
276 | usb6fire_control_streaming_update(rt); | ||
277 | changed = 1; | ||
278 | } | ||
279 | return changed; | ||
280 | } | ||
281 | |||
282 | static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, | ||
283 | struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
286 | ucontrol->value.integer.value[0] = rt->digital_thru_switch; | ||
287 | return 0; | ||
288 | } | ||
289 | |||
198 | static struct __devinitdata snd_kcontrol_new elements[] = { | 290 | static struct __devinitdata snd_kcontrol_new elements[] = { |
199 | { | 291 | { |
200 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 292 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
@@ -223,6 +315,15 @@ static struct __devinitdata snd_kcontrol_new elements[] = { | |||
223 | .get = usb6fire_control_opt_coax_get, | 315 | .get = usb6fire_control_opt_coax_get, |
224 | .put = usb6fire_control_opt_coax_put | 316 | .put = usb6fire_control_opt_coax_put |
225 | }, | 317 | }, |
318 | { | ||
319 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
320 | .name = "Digital Thru Playback Route", | ||
321 | .index = 0, | ||
322 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
323 | .info = snd_ctl_boolean_mono_info, | ||
324 | .get = usb6fire_control_digital_thru_get, | ||
325 | .put = usb6fire_control_digital_thru_put | ||
326 | }, | ||
226 | {} | 327 | {} |
227 | }; | 328 | }; |
228 | 329 | ||
@@ -238,6 +339,9 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) | |||
238 | return -ENOMEM; | 339 | return -ENOMEM; |
239 | 340 | ||
240 | rt->chip = chip; | 341 | rt->chip = chip; |
342 | rt->update_streaming = usb6fire_control_streaming_update; | ||
343 | rt->set_rate = usb6fire_control_set_rate; | ||
344 | rt->set_channels = usb6fire_control_set_channels; | ||
241 | 345 | ||
242 | i = 0; | 346 | i = 0; |
243 | while (init_data[i].type) { | 347 | while (init_data[i].type) { |
@@ -249,6 +353,7 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) | |||
249 | usb6fire_control_opt_coax_update(rt); | 353 | usb6fire_control_opt_coax_update(rt); |
250 | usb6fire_control_line_phono_update(rt); | 354 | usb6fire_control_line_phono_update(rt); |
251 | usb6fire_control_master_vol_update(rt); | 355 | usb6fire_control_master_vol_update(rt); |
356 | usb6fire_control_streaming_update(rt); | ||
252 | 357 | ||
253 | i = 0; | 358 | i = 0; |
254 | while (elements[i].name) { | 359 | while (elements[i].name) { |