File Index
Files and directories
Sign in
FILE

pcm.c

File preview with syntax highlighting.

linux-6.19.14/sound/usb/line6/pcm.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Line 6 Linux USB driver
  4 *
  5 * Copyright (C) 2004-2010 Markus Grabner (line6@grabner-graz.at)
  6 */
  7
  8#include <linux/slab.h>
  9#include <linux/export.h>
 10#include <sound/core.h>
 11#include <sound/control.h>
 12#include <sound/pcm.h>
 13#include <sound/pcm_params.h>
 14
 15#include "capture.h"
 16#include "driver.h"
 17#include "playback.h"
 18
 19/* impulse response volume controls */
 20static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
 21					 struct snd_ctl_elem_info *uinfo)
 22{
 23	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 24	uinfo->count = 1;
 25	uinfo->value.integer.min = 0;
 26	uinfo->value.integer.max = 255;
 27	return 0;
 28}
 29
 30static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
 31					struct snd_ctl_elem_value *ucontrol)
 32{
 33	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 34
 35	ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
 36	return 0;
 37}
 38
 39static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
 40					struct snd_ctl_elem_value *ucontrol)
 41{
 42	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 43	int value = ucontrol->value.integer.value[0];
 44	int err;
 45
 46	if (line6pcm->impulse_volume == value)
 47		return 0;
 48
 49	line6pcm->impulse_volume = value;
 50	if (value > 0) {
 51		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE, true);
 52		if (err < 0) {
 53			line6pcm->impulse_volume = 0;
 54			return err;
 55		}
 56	} else {
 57		line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE);
 58	}
 59	return 1;
 60}
 61
 62/* impulse response period controls */
 63static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
 64					 struct snd_ctl_elem_info *uinfo)
 65{
 66	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 67	uinfo->count = 1;
 68	uinfo->value.integer.min = 0;
 69	uinfo->value.integer.max = 2000;
 70	return 0;
 71}
 72
 73static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
 74					struct snd_ctl_elem_value *ucontrol)
 75{
 76	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 77
 78	ucontrol->value.integer.value[0] = line6pcm->impulse_period;
 79	return 0;
 80}
 81
 82static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
 83					struct snd_ctl_elem_value *ucontrol)
 84{
 85	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 86	int value = ucontrol->value.integer.value[0];
 87
 88	if (line6pcm->impulse_period == value)
 89		return 0;
 90
 91	line6pcm->impulse_period = value;
 92	return 1;
 93}
 94
 95/*
 96	Unlink all currently active URBs.
 97*/
 98static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm,
 99				    struct line6_pcm_stream *pcms)
100{
101	int i;
102
103	for (i = 0; i < line6pcm->line6->iso_buffers; i++) {
104		if (test_bit(i, &pcms->active_urbs)) {
105			if (!test_and_set_bit(i, &pcms->unlink_urbs))
106				usb_unlink_urb(pcms->urbs[i]);
107		}
108	}
109}
110
111/*
112	Wait until unlinking of all currently active URBs has been finished.
113*/
114static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm,
115					struct line6_pcm_stream *pcms)
116{
117	int timeout = HZ;
118	int i;
119	int alive;
120
121	do {
122		alive = 0;
123		for (i = 0; i < line6pcm->line6->iso_buffers; i++) {
124			if (test_bit(i, &pcms->active_urbs))
125				alive++;
126		}
127		if (!alive)
128			break;
129		set_current_state(TASK_UNINTERRUPTIBLE);
130		schedule_timeout(1);
131	} while (--timeout > 0);
132	if (alive)
133		dev_err(line6pcm->line6->ifcdev,
134			"timeout: still %d active urbs..\n", alive);
135}
136
137static inline struct line6_pcm_stream *
138get_stream(struct snd_line6_pcm *line6pcm, int direction)
139{
140	return (direction == SNDRV_PCM_STREAM_PLAYBACK) ?
141		&line6pcm->out : &line6pcm->in;
142}
143
144/* allocate a buffer if not opened yet;
145 * call this in line6pcm.state_mutex
146 */
147static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm,
148				struct line6_pcm_stream *pstr, int direction, int type)
149{
150	const int pkt_size =
151		(direction == SNDRV_PCM_STREAM_PLAYBACK) ?
152			line6pcm->max_packet_size_out :
153			line6pcm->max_packet_size_in;
154
155	/* Invoked multiple times in a row so allocate once only */
156	if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) {
157		pstr->buffer =
158			kmalloc(array3_size(line6pcm->line6->iso_buffers,
159					    LINE6_ISO_PACKETS, pkt_size),
160				GFP_KERNEL);
161		if (!pstr->buffer)
162			return -ENOMEM;
163	}
164	return 0;
165}
166
167/* free a buffer if all streams are closed;
168 * call this in line6pcm.state_mutex
169 */
170static void line6_buffer_release(struct snd_line6_pcm *line6pcm,
171				 struct line6_pcm_stream *pstr, int type)
172{
173	clear_bit(type, &pstr->opened);
174	if (!pstr->opened) {
175		line6_wait_clear_audio_urbs(line6pcm, pstr);
176		kfree(pstr->buffer);
177		pstr->buffer = NULL;
178	}
179}
180
181/* start a PCM stream */
182static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction,
183			      int type)
184{
185	struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
186	int ret = 0;
187
188	guard(spinlock_irqsave)(&pstr->lock);
189	if (!test_and_set_bit(type, &pstr->running) &&
190	    !(pstr->active_urbs || pstr->unlink_urbs)) {
191		pstr->count = 0;
192		/* Submit all currently available URBs */
193		if (direction == SNDRV_PCM_STREAM_PLAYBACK)
194			ret = line6_submit_audio_out_all_urbs(line6pcm);
195		else
196			ret = line6_submit_audio_in_all_urbs(line6pcm);
197	}
198
199	if (ret < 0)
200		clear_bit(type, &pstr->running);
201	return ret;
202}
203
204/* stop a PCM stream; this doesn't sync with the unlinked URBs */
205static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction,
206			  int type)
207{
208	struct line6_pcm_stream *pstr = get_stream(line6pcm, direction);
209
210	scoped_guard(spinlock_irqsave, &pstr->lock) {
211		clear_bit(type, &pstr->running);
212		if (pstr->running)
213			return;
214	}
215
216	line6_unlink_audio_urbs(line6pcm, pstr);
217	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
218		guard(spinlock_irqsave)(&pstr->lock);
219		line6pcm->prev_fbuf = NULL;
220		line6pcm->prev_fsize = 0;
221	}
222}
223
224/* common PCM trigger callback */
225int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
226{
227	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
228	struct snd_pcm_substream *s;
229	int err;
230
231	clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags);
232
233	snd_pcm_group_for_each_entry(s, substream) {
234		if (s->pcm->card != substream->pcm->card)
235			continue;
236
237		switch (cmd) {
238		case SNDRV_PCM_TRIGGER_START:
239		case SNDRV_PCM_TRIGGER_RESUME:
240			if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
241				(line6pcm->line6->properties->capabilities &
242					LINE6_CAP_IN_NEEDS_OUT)) {
243				err = line6_stream_start(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
244						 LINE6_STREAM_CAPTURE_HELPER);
245				if (err < 0)
246					return err;
247			}
248			err = line6_stream_start(line6pcm, s->stream,
249						 LINE6_STREAM_PCM);
250			if (err < 0)
251				return err;
252			break;
253
254		case SNDRV_PCM_TRIGGER_STOP:
255		case SNDRV_PCM_TRIGGER_SUSPEND:
256			if (s->stream == SNDRV_PCM_STREAM_CAPTURE &&
257				(line6pcm->line6->properties->capabilities &
258					LINE6_CAP_IN_NEEDS_OUT)) {
259				line6_stream_stop(line6pcm, SNDRV_PCM_STREAM_PLAYBACK,
260					  LINE6_STREAM_CAPTURE_HELPER);
261			}
262			line6_stream_stop(line6pcm, s->stream,
263					  LINE6_STREAM_PCM);
264			break;
265
266		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
267			if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
268				return -EINVAL;
269			set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
270			break;
271
272		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
273			if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
274				return -EINVAL;
275			clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags);
276			break;
277
278		default:
279			return -EINVAL;
280		}
281	}
282
283	return 0;
284}
285
286/* common PCM pointer callback */
287snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream)
288{
289	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
290	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
291
292	return pstr->pos_done;
293}
294
295/* Stop and release duplex streams */
296static void __line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
297{
298	struct line6_pcm_stream *pstr;
299	int dir;
300
301	for (dir = 0; dir < 2; dir++)
302		line6_stream_stop(line6pcm, dir, type);
303	for (dir = 0; dir < 2; dir++) {
304		pstr = get_stream(line6pcm, dir);
305		line6_buffer_release(line6pcm, pstr, type);
306	}
307}
308
309/* Stop and release duplex streams */
310void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type)
311{
312	guard(mutex)(&line6pcm->state_mutex);
313	__line6_pcm_release(line6pcm, type);
314}
315EXPORT_SYMBOL_GPL(line6_pcm_release);
316
317/* Acquire and optionally start duplex streams:
318 * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR
319 */
320int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type, bool start)
321{
322	struct line6_pcm_stream *pstr;
323	int ret = 0, dir;
324
325	/* TODO: We should assert SNDRV_PCM_STREAM_PLAYBACK/CAPTURE == 0/1 */
326	guard(mutex)(&line6pcm->state_mutex);
327	for (dir = 0; dir < 2; dir++) {
328		pstr = get_stream(line6pcm, dir);
329		ret = line6_buffer_acquire(line6pcm, pstr, dir, type);
330		if (ret < 0)
331			goto error;
332		if (!pstr->running)
333			line6_wait_clear_audio_urbs(line6pcm, pstr);
334	}
335	if (start) {
336		for (dir = 0; dir < 2; dir++) {
337			ret = line6_stream_start(line6pcm, dir, type);
338			if (ret < 0)
339				goto error;
340		}
341	}
342 error:
343	if (ret < 0)
344		__line6_pcm_release(line6pcm, type);
345	return ret;
346}
347EXPORT_SYMBOL_GPL(line6_pcm_acquire);
348
349/* common PCM hw_params callback */
350int snd_line6_hw_params(struct snd_pcm_substream *substream,
351			struct snd_pcm_hw_params *hw_params)
352{
353	int ret;
354	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
355	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
356
357	guard(mutex)(&line6pcm->state_mutex);
358	ret = line6_buffer_acquire(line6pcm, pstr, substream->stream,
359	                           LINE6_STREAM_PCM);
360	if (ret < 0)
361		return ret;
362
363	pstr->period = params_period_bytes(hw_params);
364	return 0;
365}
366
367/* common PCM hw_free callback */
368int snd_line6_hw_free(struct snd_pcm_substream *substream)
369{
370	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
371	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
372
373	guard(mutex)(&line6pcm->state_mutex);
374	line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM);
375	return 0;
376}
377
378
379/* control info callback */
380static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
381					   struct snd_ctl_elem_info *uinfo)
382{
383	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
384	uinfo->count = 2;
385	uinfo->value.integer.min = 0;
386	uinfo->value.integer.max = 256;
387	return 0;
388}
389
390/* control get callback */
391static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
392					  struct snd_ctl_elem_value *ucontrol)
393{
394	int i;
395	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
396
397	for (i = 0; i < 2; i++)
398		ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
399
400	return 0;
401}
402
403/* control put callback */
404static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
405					  struct snd_ctl_elem_value *ucontrol)
406{
407	int i, changed = 0;
408	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
409
410	for (i = 0; i < 2; i++)
411		if (line6pcm->volume_playback[i] !=
412		    ucontrol->value.integer.value[i]) {
413			line6pcm->volume_playback[i] =
414			    ucontrol->value.integer.value[i];
415			changed = 1;
416		}
417
418	return changed;
419}
420
421/* control definition */
422static const struct snd_kcontrol_new line6_controls[] = {
423	{
424		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
425		.name = "PCM Playback Volume",
426		.info = snd_line6_control_playback_info,
427		.get = snd_line6_control_playback_get,
428		.put = snd_line6_control_playback_put
429	},
430	{
431		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
432		.name = "Impulse Response Volume",
433		.info = snd_line6_impulse_volume_info,
434		.get = snd_line6_impulse_volume_get,
435		.put = snd_line6_impulse_volume_put
436	},
437	{
438		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
439		.name = "Impulse Response Period",
440		.info = snd_line6_impulse_period_info,
441		.get = snd_line6_impulse_period_get,
442		.put = snd_line6_impulse_period_put
443	},
444};
445
446/*
447	Cleanup the PCM device.
448*/
449static void cleanup_urbs(struct line6_pcm_stream *pcms, int iso_buffers)
450{
451	int i;
452
453	/* Most likely impossible in current code... */
454	if (pcms->urbs == NULL)
455		return;
456
457	for (i = 0; i < iso_buffers; i++) {
458		if (pcms->urbs[i]) {
459			usb_kill_urb(pcms->urbs[i]);
460			usb_free_urb(pcms->urbs[i]);
461		}
462	}
463	kfree(pcms->urbs);
464	pcms->urbs = NULL;
465}
466
467static void line6_cleanup_pcm(struct snd_pcm *pcm)
468{
469	struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
470
471	cleanup_urbs(&line6pcm->out, line6pcm->line6->iso_buffers);
472	cleanup_urbs(&line6pcm->in, line6pcm->line6->iso_buffers);
473	kfree(line6pcm);
474}
475
476/* create a PCM device */
477static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
478{
479	struct snd_pcm *pcm;
480	int err;
481
482	err = snd_pcm_new(line6->card, (char *)line6->properties->name,
483			  0, 1, 1, pcm_ret);
484	if (err < 0)
485		return err;
486	pcm = *pcm_ret;
487	strscpy(pcm->name, line6->properties->name);
488
489	/* set operators */
490	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
491			&snd_line6_playback_ops);
492	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
493
494	/* pre-allocation of buffers */
495	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
496				       NULL, 64 * 1024, 128 * 1024);
497	return 0;
498}
499
500/*
501	Sync with PCM stream stops.
502*/
503void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
504{
505	line6_unlink_audio_urbs(line6pcm, &line6pcm->out);
506	line6_unlink_audio_urbs(line6pcm, &line6pcm->in);
507	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out);
508	line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in);
509}
510
511/*
512	Create and register the PCM device and mixer entries.
513	Create URBs for playback and capture.
514*/
515int line6_init_pcm(struct usb_line6 *line6,
516		   struct line6_pcm_properties *properties)
517{
518	int i, err;
519	unsigned ep_read = line6->properties->ep_audio_r;
520	unsigned ep_write = line6->properties->ep_audio_w;
521	struct snd_pcm *pcm;
522	struct snd_line6_pcm *line6pcm;
523
524	if (!(line6->properties->capabilities & LINE6_CAP_PCM))
525		return 0;	/* skip PCM initialization and report success */
526
527	err = snd_line6_new_pcm(line6, &pcm);
528	if (err < 0)
529		return err;
530
531	line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
532	if (!line6pcm)
533		return -ENOMEM;
534
535	mutex_init(&line6pcm->state_mutex);
536	line6pcm->pcm = pcm;
537	line6pcm->properties = properties;
538	line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
539	line6pcm->volume_monitor = 255;
540	line6pcm->line6 = line6;
541
542	spin_lock_init(&line6pcm->out.lock);
543	spin_lock_init(&line6pcm->in.lock);
544	line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
545
546	line6->line6pcm = line6pcm;
547
548	pcm->private_data = line6pcm;
549	pcm->private_free = line6_cleanup_pcm;
550
551	line6pcm->max_packet_size_in =
552		usb_maxpacket(line6->usbdev,
553			usb_rcvisocpipe(line6->usbdev, ep_read));
554	line6pcm->max_packet_size_out =
555		usb_maxpacket(line6->usbdev,
556			usb_sndisocpipe(line6->usbdev, ep_write));
557	if (!line6pcm->max_packet_size_in || !line6pcm->max_packet_size_out) {
558		dev_err(line6pcm->line6->ifcdev,
559			"cannot get proper max packet size\n");
560		return -EINVAL;
561	}
562
563	err = line6_create_audio_out_urbs(line6pcm);
564	if (err < 0)
565		return err;
566
567	err = line6_create_audio_in_urbs(line6pcm);
568	if (err < 0)
569		return err;
570
571	/* mixer: */
572	for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
573		err = snd_ctl_add(line6->card,
574				  snd_ctl_new1(&line6_controls[i], line6pcm));
575		if (err < 0)
576			return err;
577	}
578
579	return 0;
580}
581EXPORT_SYMBOL_GPL(line6_init_pcm);
582
583/* prepare pcm callback */
584int snd_line6_prepare(struct snd_pcm_substream *substream)
585{
586	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
587	struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream);
588
589	guard(mutex)(&line6pcm->state_mutex);
590	if (!pstr->running)
591		line6_wait_clear_audio_urbs(line6pcm, pstr);
592
593	if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) {
594		line6pcm->out.count = 0;
595		line6pcm->out.pos = 0;
596		line6pcm->out.pos_done = 0;
597		line6pcm->out.bytes = 0;
598		line6pcm->in.count = 0;
599		line6pcm->in.pos_done = 0;
600		line6pcm->in.bytes = 0;
601	}
602
603	return 0;
604}
~/ Read-only file preview.