File Index
Files and directories
Sign in
FILE

us144mkii_controls.c

File preview with syntax highlighting.

linux-6.19.14/sound/usb/usx2y/us144mkii_controls.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2// Copyright (c) 2025 Ĺ erif Rami <ramiserifpersia@gmail.com>
  3
  4#include "us144mkii.h"
  5
  6/**
  7 * @brief Text descriptions for playback output source options.
  8 *
  9 * Used by ALSA kcontrol elements to provide user-friendly names for
 10 * the playback routing options (e.g., "Playback 1-2", "Playback 3-4").
 11 */
 12static const char *const playback_source_texts[] = { "Playback 1-2",
 13						     "Playback 3-4" };
 14
 15/**
 16 * @brief Text descriptions for capture input source options.
 17 *
 18 * Used by ALSA kcontrol elements to provide user-friendly names for
 19 * the capture routing options (e.g., "Analog In", "Digital In").
 20 */
 21static const char *const capture_source_texts[] = { "Analog In", "Digital In" };
 22
 23/**
 24 * tascam_playback_source_info() - ALSA control info callback for playback
 25 * source.
 26 * @kcontrol: The ALSA kcontrol instance.
 27 * @uinfo: The ALSA control element info structure to fill.
 28 *
 29 * This function provides information about the enumerated playback source
 30 * control, including its type, count, and available items (Playback 1-2,
 31 * Playback 3-4).
 32 *
 33 * Return: 0 on success.
 34 */
 35static int tascam_playback_source_info(struct snd_kcontrol *kcontrol,
 36				       struct snd_ctl_elem_info *uinfo)
 37{
 38	return snd_ctl_enum_info(uinfo, 1, 2, playback_source_texts);
 39}
 40
 41/**
 42 * tascam_line_out_get() - ALSA control get callback for Line Outputs Source.
 43 * @kcontrol: The ALSA kcontrol instance.
 44 * @ucontrol: The ALSA control element value structure to fill.
 45 *
 46 * This function retrieves the current selection for the Line Outputs source
 47 * (Playback 1-2 or Playback 3-4) from the driver's private data and populates
 48 * the ALSA control element value.
 49 *
 50 * Return: 0 on success.
 51 */
 52static int tascam_line_out_get(struct snd_kcontrol *kcontrol,
 53			       struct snd_ctl_elem_value *ucontrol)
 54{
 55	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
 56
 57	scoped_guard(spinlock_irqsave, &tascam->lock) {
 58		ucontrol->value.enumerated.item[0] = tascam->line_out_source;
 59	}
 60	return 0;
 61}
 62
 63/**
 64 * tascam_line_out_put() - ALSA control put callback for Line Outputs Source.
 65 * @kcontrol: The ALSA kcontrol instance.
 66 * @ucontrol: The ALSA control element value structure containing the new value.
 67 *
 68 * This function sets the Line Outputs source (Playback 1-2 or Playback 3-4)
 69 * based on the user's selection from the ALSA control element. It validates
 70 * the input and updates the driver's private data.
 71 *
 72 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
 73 */
 74static int tascam_line_out_put(struct snd_kcontrol *kcontrol,
 75			       struct snd_ctl_elem_value *ucontrol)
 76{
 77	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
 78	int changed = 0;
 79
 80	if (ucontrol->value.enumerated.item[0] > 1)
 81		return -EINVAL;
 82
 83	scoped_guard(spinlock_irqsave, &tascam->lock) {
 84		if (tascam->line_out_source != ucontrol->value.enumerated.item[0]) {
 85			tascam->line_out_source = ucontrol->value.enumerated.item[0];
 86			changed = 1;
 87		}
 88	}
 89	return changed;
 90}
 91
 92/**
 93 * tascam_line_out_control - ALSA kcontrol definition for Line Outputs Source.
 94 *
 95 * This defines a new ALSA mixer control named "Line OUTPUTS Source" that allows
 96 * the user to select between "Playback 1-2" and "Playback 3-4" for the analog
 97 * line outputs of the device. It uses the `tascam_playback_source_info` for
 98 * information and `tascam_line_out_get`/`tascam_line_out_put` for value
 99 * handling.
100 */
101static const struct snd_kcontrol_new tascam_line_out_control = {
102	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
103	.name = "Line Playback Source",
104	.info = tascam_playback_source_info,
105	.get = tascam_line_out_get,
106	.put = tascam_line_out_put,
107};
108
109/**
110 * tascam_digital_out_get() - ALSA control get callback for Digital Outputs
111 * Source.
112 * @kcontrol: The ALSA kcontrol instance.
113 * @ucontrol: The ALSA control element value structure to fill.
114 *
115 * This function retrieves the current selection for the Digital Outputs source
116 * (Playback 1-2 or Playback 3-4) from the driver's private data and populates
117 * the ALSA control element value.
118 *
119 * Return: 0 on success.
120 */
121static int tascam_digital_out_get(struct snd_kcontrol *kcontrol,
122				  struct snd_ctl_elem_value *ucontrol)
123{
124	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
125
126	scoped_guard(spinlock_irqsave, &tascam->lock) {
127		ucontrol->value.enumerated.item[0] = tascam->digital_out_source;
128	}
129	return 0;
130}
131
132/**
133 * tascam_digital_out_put() - ALSA control put callback for Digital Outputs
134 * Source.
135 * @kcontrol: The ALSA kcontrol instance.
136 * @ucontrol: The ALSA control element value structure containing the new value.
137 *
138 * This function sets the Digital Outputs source (Playback 1-2 or Playback 3-4)
139 * based on the user's selection from the ALSA control element. It validates
140 * the input and updates the driver's private data.
141 *
142 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
143 */
144static int tascam_digital_out_put(struct snd_kcontrol *kcontrol,
145				  struct snd_ctl_elem_value *ucontrol)
146{
147	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
148	int changed = 0;
149
150	if (ucontrol->value.enumerated.item[0] > 1)
151		return -EINVAL;
152
153	scoped_guard(spinlock_irqsave, &tascam->lock) {
154		if (tascam->digital_out_source != ucontrol->value.enumerated.item[0]) {
155			tascam->digital_out_source = ucontrol->value.enumerated.item[0];
156			changed = 1;
157		}
158	}
159	return changed;
160}
161
162/**
163 * tascam_digital_out_control - ALSA kcontrol definition for Digital Outputs
164 * Source.
165 *
166 * This defines a new ALSA mixer control named "Digital OUTPUTS Source" that
167 * allows the user to select between "Playback 1-2" and "Playback 3-4" for the
168 * digital outputs of the device. It uses the `tascam_playback_source_info` for
169 * information and `tascam_digital_out_get`/`tascam_digital_out_put` for value
170 * handling.
171 */
172static const struct snd_kcontrol_new tascam_digital_out_control = {
173	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
174	.name = "Digital Playback Source",
175	.info = tascam_playback_source_info,
176	.get = tascam_digital_out_get,
177	.put = tascam_digital_out_put,
178};
179
180/**
181 * tascam_capture_source_info() - ALSA control info callback for capture source.
182 * @kcontrol: The ALSA kcontrol instance.
183 * @uinfo: The ALSA control element info structure to fill.
184 *
185 * This function provides information about the enumerated capture source
186 * control, including its type, count, and available items (Analog In, Digital
187 * In).
188 *
189 * Return: 0 on success.
190 */
191static int tascam_capture_source_info(struct snd_kcontrol *kcontrol,
192				      struct snd_ctl_elem_info *uinfo)
193{
194	return snd_ctl_enum_info(uinfo, 1, 2, capture_source_texts);
195}
196
197/**
198 * tascam_capture_12_get() - ALSA control get callback for Capture channels 1
199 * and 2 Source.
200 * @kcontrol: The ALSA kcontrol instance.
201 * @ucontrol: The ALSA control element value structure to fill.
202 *
203 * This function retrieves the current selection for the Capture channels 1 and
204 * 2 source (Analog In or Digital In) from the driver's private data and
205 * populates the ALSA control element value.
206 *
207 * Return: 0 on success.
208 */
209static int tascam_capture_12_get(struct snd_kcontrol *kcontrol,
210				 struct snd_ctl_elem_value *ucontrol)
211{
212	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
213
214	scoped_guard(spinlock_irqsave, &tascam->lock) {
215		ucontrol->value.enumerated.item[0] = tascam->capture_12_source;
216	}
217	return 0;
218}
219
220/**
221 * tascam_capture_12_put() - ALSA control put callback for Capture channels 1
222 * and 2 Source.
223 * @kcontrol: The ALSA kcontrol instance.
224 * @ucontrol: The ALSA control element value structure containing the new value.
225 *
226 * This function sets the Capture channels 1 and 2 source (Analog In or Digital
227 * In) based on the user's selection from the ALSA control element. It validates
228 * the input and updates the driver's private data.
229 *
230 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
231 */
232static int tascam_capture_12_put(struct snd_kcontrol *kcontrol,
233				 struct snd_ctl_elem_value *ucontrol)
234{
235	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
236	int changed = 0;
237
238	if (ucontrol->value.enumerated.item[0] > 1)
239		return -EINVAL;
240
241	scoped_guard(spinlock_irqsave, &tascam->lock) {
242		if (tascam->capture_12_source != ucontrol->value.enumerated.item[0]) {
243			tascam->capture_12_source = ucontrol->value.enumerated.item[0];
244			changed = 1;
245		}
246	}
247	return changed;
248}
249
250/**
251 * tascam_capture_12_control - ALSA kcontrol definition for Capture channels 1
252 * and 2 Source.
253 *
254 * This defines a new ALSA mixer control named "ch1 and ch2 Source" that allows
255 * the user to select between "Analog In" and "Digital In" for the first two
256 * capture channels of the device. It uses the `tascam_capture_source_info` for
257 * information and `tascam_capture_12_get`/`tascam_capture_12_put` for value
258 * handling.
259 */
260static const struct snd_kcontrol_new tascam_capture_12_control = {
261	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
262	.name = "Ch1/2 Capture Source",
263	.info = tascam_capture_source_info,
264	.get = tascam_capture_12_get,
265	.put = tascam_capture_12_put,
266};
267
268/**
269 * tascam_capture_34_get() - ALSA control get callback for Capture channels 3
270 * and 4 Source.
271 * @kcontrol: The ALSA kcontrol instance.
272 * @ucontrol: The ALSA control element value structure to fill.
273 *
274 * This function retrieves the current selection for the Capture channels 3 and
275 * 4 source (Analog In or Digital In) from the driver's private data and
276 * populates the ALSA control element value.
277 *
278 * Return: 0 on success.
279 */
280static int tascam_capture_34_get(struct snd_kcontrol *kcontrol,
281				 struct snd_ctl_elem_value *ucontrol)
282{
283	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
284
285	scoped_guard(spinlock_irqsave, &tascam->lock) {
286		ucontrol->value.enumerated.item[0] = tascam->capture_34_source;
287	}
288	return 0;
289}
290
291/**
292 * tascam_capture_34_put() - ALSA control put callback for Capture channels 3
293 * and 4 Source.
294 * @kcontrol: The ALSA kcontrol instance.
295 * @ucontrol: The ALSA control element value structure containing the new value.
296 *
297 * This function sets the Capture channels 3 and 4 source (Analog In or Digital
298 * In) based on the user's selection from the ALSA control element. It validates
299 * the input and updates the driver's private data.
300 *
301 * Return: 1 if the value was changed, 0 if unchanged, or a negative error code.
302 */
303static int tascam_capture_34_put(struct snd_kcontrol *kcontrol,
304				 struct snd_ctl_elem_value *ucontrol)
305{
306	struct tascam_card *tascam = snd_kcontrol_chip(kcontrol);
307	int changed = 0;
308
309	if (ucontrol->value.enumerated.item[0] > 1)
310		return -EINVAL;
311
312	scoped_guard(spinlock_irqsave, &tascam->lock) {
313		if (tascam->capture_34_source != ucontrol->value.enumerated.item[0]) {
314			tascam->capture_34_source = ucontrol->value.enumerated.item[0];
315			changed = 1;
316		}
317	}
318	return changed;
319}
320
321/**
322 * tascam_capture_34_control - ALSA kcontrol definition for Capture channels 3
323 * and 4 Source.
324 *
325 * This defines a new ALSA mixer control named "ch3 and ch4 Source" that allows
326 * the user to select between "Analog In" and "Digital In" for the third and
327 * fourth capture channels of the device. It uses the
328 * `tascam_capture_source_info` for information and
329 * `tascam_capture_34_get`/`tascam_capture_34_put` for value handling.
330 */
331static const struct snd_kcontrol_new tascam_capture_34_control = {
332	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
333	.name = "Ch3/4 Capture Source",
334	.info = tascam_capture_source_info,
335	.get = tascam_capture_34_get,
336	.put = tascam_capture_34_put,
337};
338
339/**
340 * tascam_samplerate_info() - ALSA control info callback for Sample Rate.
341 * @kcontrol: The ALSA kcontrol instance.
342 * @uinfo: The ALSA control element info structure to fill.
343 *
344 * This function provides information about the Sample Rate control, defining
345 * it as an integer type with a minimum value of 0 and a maximum of 96000.
346 *
347 * Return: 0 on success.
348 */
349static int tascam_samplerate_info(struct snd_kcontrol *kcontrol,
350				  struct snd_ctl_elem_info *uinfo)
351{
352	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
353	uinfo->count = 1;
354	uinfo->value.integer.min = 0;
355	uinfo->value.integer.max = 96000;
356	return 0;
357}
358
359/**
360 * tascam_samplerate_get() - ALSA control get callback for Sample Rate.
361 * @kcontrol: The ALSA kcontrol instance.
362 * @ucontrol: The ALSA control element value structure to fill.
363 *
364 * This function retrieves the current sample rate from the device via a USB
365 * control message and populates the ALSA control element value. If the rate
366 * is already known (i.e., `current_rate` is set), it returns that value
367 * directly.
368 *
369 * Return: 0 on success, or a negative error code on failure.
370 */
371static int tascam_samplerate_get(struct snd_kcontrol *kcontrol,
372				 struct snd_ctl_elem_value *ucontrol)
373{
374	struct tascam_card *tascam =
375		(struct tascam_card *)snd_kcontrol_chip(kcontrol);
376	int err;
377	u32 rate = 0;
378
379	scoped_guard(spinlock_irqsave, &tascam->lock) {
380		if (tascam->current_rate > 0) {
381			ucontrol->value.integer.value[0] = tascam->current_rate;
382			return 0;
383		}
384	}
385
386	u8 *buf __free(kfree) =
387		kmalloc(3, GFP_KERNEL);
388	if (!buf)
389		return -ENOMEM;
390
391	err = usb_control_msg(tascam->dev, usb_rcvctrlpipe(tascam->dev, 0),
392			      UAC_GET_CUR, RT_D2H_CLASS_EP,
393			      UAC_SAMPLING_FREQ_CONTROL, EP_AUDIO_IN, buf, 3,
394			      USB_CTRL_TIMEOUT_MS);
395
396	if (err >= 3)
397		rate = buf[0] | (buf[1] << 8) | (buf[2] << 16);
398
399	ucontrol->value.integer.value[0] = rate;
400	return 0;
401}
402
403/**
404 * tascam_samplerate_control - ALSA kcontrol definition for Sample Rate.
405 *
406 * This defines a new ALSA mixer control named "Sample Rate" that displays
407 * the current sample rate of the device. It is a read-only control.
408 */
409static const struct snd_kcontrol_new tascam_samplerate_control = {
410	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
411	.name = "Sample Rate",
412	.info = tascam_samplerate_info,
413	.get = tascam_samplerate_get,
414	.access = SNDRV_CTL_ELEM_ACCESS_READ,
415};
416
417int tascam_create_controls(struct tascam_card *tascam)
418{
419	int err;
420
421	err = snd_ctl_add(tascam->card,
422			  snd_ctl_new1(&tascam_line_out_control, tascam));
423	if (err < 0)
424		return err;
425	err = snd_ctl_add(tascam->card,
426			  snd_ctl_new1(&tascam_digital_out_control, tascam));
427	if (err < 0)
428		return err;
429	err = snd_ctl_add(tascam->card,
430			  snd_ctl_new1(&tascam_capture_12_control, tascam));
431	if (err < 0)
432		return err;
433	err = snd_ctl_add(tascam->card,
434			  snd_ctl_new1(&tascam_capture_34_control, tascam));
435	if (err < 0)
436		return err;
437
438	err = snd_ctl_add(tascam->card,
439			  snd_ctl_new1(&tascam_samplerate_control, tascam));
440	if (err < 0)
441		return err;
442
443	return 0;
444}
~/ Read-only file preview.