xref: /kernel/linux/linux-6.6/sound/usb/caiaq/audio.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *   Copyright (c) 2006-2008 Daniel Mack, Karsten Wiese
462306a36Sopenharmony_ci*/
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/spinlock.h>
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/usb.h>
1162306a36Sopenharmony_ci#include <sound/core.h>
1262306a36Sopenharmony_ci#include <sound/pcm.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "device.h"
1562306a36Sopenharmony_ci#include "audio.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define N_URBS			32
1862306a36Sopenharmony_ci#define CLOCK_DRIFT_TOLERANCE	5
1962306a36Sopenharmony_ci#define FRAMES_PER_URB		8
2062306a36Sopenharmony_ci#define BYTES_PER_FRAME		512
2162306a36Sopenharmony_ci#define CHANNELS_PER_STREAM	2
2262306a36Sopenharmony_ci#define BYTES_PER_SAMPLE	3
2362306a36Sopenharmony_ci#define BYTES_PER_SAMPLE_USB	4
2462306a36Sopenharmony_ci#define MAX_BUFFER_SIZE		(128*1024)
2562306a36Sopenharmony_ci#define MAX_ENDPOINT_SIZE	512
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define ENDPOINT_CAPTURE	2
2862306a36Sopenharmony_ci#define ENDPOINT_PLAYBACK	6
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define MAKE_CHECKBYTE(cdev,stream,i) \
3162306a36Sopenharmony_ci	(stream << 1) | (~(i / (cdev->n_streams * BYTES_PER_SAMPLE_USB)) & 1)
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic const struct snd_pcm_hardware snd_usb_caiaq_pcm_hardware = {
3462306a36Sopenharmony_ci	.info 		= (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
3562306a36Sopenharmony_ci			   SNDRV_PCM_INFO_BLOCK_TRANSFER),
3662306a36Sopenharmony_ci	.formats 	= SNDRV_PCM_FMTBIT_S24_3BE,
3762306a36Sopenharmony_ci	.rates 		= (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
3862306a36Sopenharmony_ci			   SNDRV_PCM_RATE_96000),
3962306a36Sopenharmony_ci	.rate_min	= 44100,
4062306a36Sopenharmony_ci	.rate_max	= 0, /* will overwrite later */
4162306a36Sopenharmony_ci	.channels_min	= CHANNELS_PER_STREAM,
4262306a36Sopenharmony_ci	.channels_max	= CHANNELS_PER_STREAM,
4362306a36Sopenharmony_ci	.buffer_bytes_max = MAX_BUFFER_SIZE,
4462306a36Sopenharmony_ci	.period_bytes_min = 128,
4562306a36Sopenharmony_ci	.period_bytes_max = MAX_BUFFER_SIZE,
4662306a36Sopenharmony_ci	.periods_min	= 1,
4762306a36Sopenharmony_ci	.periods_max	= 1024,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void
5162306a36Sopenharmony_ciactivate_substream(struct snd_usb_caiaqdev *cdev,
5262306a36Sopenharmony_ci	           struct snd_pcm_substream *sub)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	spin_lock(&cdev->spinlock);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
5762306a36Sopenharmony_ci		cdev->sub_playback[sub->number] = sub;
5862306a36Sopenharmony_ci	else
5962306a36Sopenharmony_ci		cdev->sub_capture[sub->number] = sub;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	spin_unlock(&cdev->spinlock);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic void
6562306a36Sopenharmony_cideactivate_substream(struct snd_usb_caiaqdev *cdev,
6662306a36Sopenharmony_ci		     struct snd_pcm_substream *sub)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	unsigned long flags;
6962306a36Sopenharmony_ci	spin_lock_irqsave(&cdev->spinlock, flags);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
7262306a36Sopenharmony_ci		cdev->sub_playback[sub->number] = NULL;
7362306a36Sopenharmony_ci	else
7462306a36Sopenharmony_ci		cdev->sub_capture[sub->number] = NULL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	spin_unlock_irqrestore(&cdev->spinlock, flags);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int
8062306a36Sopenharmony_ciall_substreams_zero(struct snd_pcm_substream **subs)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	int i;
8362306a36Sopenharmony_ci	for (i = 0; i < MAX_STREAMS; i++)
8462306a36Sopenharmony_ci		if (subs[i] != NULL)
8562306a36Sopenharmony_ci			return 0;
8662306a36Sopenharmony_ci	return 1;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int stream_start(struct snd_usb_caiaqdev *cdev)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	int i, ret;
9262306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (cdev->streaming)
9762306a36Sopenharmony_ci		return -EINVAL;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
10062306a36Sopenharmony_ci	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
10162306a36Sopenharmony_ci	cdev->input_panic = 0;
10262306a36Sopenharmony_ci	cdev->output_panic = 0;
10362306a36Sopenharmony_ci	cdev->first_packet = 4;
10462306a36Sopenharmony_ci	cdev->streaming = 1;
10562306a36Sopenharmony_ci	cdev->warned = 0;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++) {
10862306a36Sopenharmony_ci		ret = usb_submit_urb(cdev->data_urbs_in[i], GFP_ATOMIC);
10962306a36Sopenharmony_ci		if (ret) {
11062306a36Sopenharmony_ci			dev_err(dev, "unable to trigger read #%d! (ret %d)\n",
11162306a36Sopenharmony_ci				i, ret);
11262306a36Sopenharmony_ci			cdev->streaming = 0;
11362306a36Sopenharmony_ci			return -EPIPE;
11462306a36Sopenharmony_ci		}
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return 0;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void stream_stop(struct snd_usb_caiaqdev *cdev)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	int i;
12362306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
12662306a36Sopenharmony_ci	if (!cdev->streaming)
12762306a36Sopenharmony_ci		return;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	cdev->streaming = 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++) {
13262306a36Sopenharmony_ci		usb_kill_urb(cdev->data_urbs_in[i]);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		if (test_bit(i, &cdev->outurb_active_mask))
13562306a36Sopenharmony_ci			usb_kill_urb(cdev->data_urbs_out[i]);
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	cdev->outurb_active_mask = 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_cistatic int snd_usb_caiaq_substream_open(struct snd_pcm_substream *substream)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
14462306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, substream);
14762306a36Sopenharmony_ci	substream->runtime->hw = cdev->pcm_info;
14862306a36Sopenharmony_ci	snd_pcm_limit_hw_rates(substream->runtime);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return 0;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic int snd_usb_caiaq_substream_close(struct snd_pcm_substream *substream)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
15662306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, substream);
15962306a36Sopenharmony_ci	if (all_substreams_zero(cdev->sub_playback) &&
16062306a36Sopenharmony_ci	    all_substreams_zero(cdev->sub_capture)) {
16162306a36Sopenharmony_ci		/* when the last client has stopped streaming,
16262306a36Sopenharmony_ci		 * all sample rates are allowed again */
16362306a36Sopenharmony_ci		stream_stop(cdev);
16462306a36Sopenharmony_ci		cdev->pcm_info.rates = cdev->samplerates;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	return 0;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic int snd_usb_caiaq_pcm_hw_free(struct snd_pcm_substream *sub)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
17362306a36Sopenharmony_ci	deactivate_substream(cdev, sub);
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci/* this should probably go upstream */
17862306a36Sopenharmony_ci#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
17962306a36Sopenharmony_ci#error "Change this table"
18062306a36Sopenharmony_ci#endif
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistatic const unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100,
18362306a36Sopenharmony_ci				48000, 64000, 88200, 96000, 176400, 192000 };
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic int snd_usb_caiaq_pcm_prepare(struct snd_pcm_substream *substream)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	int bytes_per_sample, bpp, ret, i;
18862306a36Sopenharmony_ci	int index = substream->number;
18962306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(substream);
19062306a36Sopenharmony_ci	struct snd_pcm_runtime *runtime = substream->runtime;
19162306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, substream);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
19662306a36Sopenharmony_ci		int out_pos;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		switch (cdev->spec.data_alignment) {
19962306a36Sopenharmony_ci		case 0:
20062306a36Sopenharmony_ci		case 2:
20162306a36Sopenharmony_ci			out_pos = BYTES_PER_SAMPLE + 1;
20262306a36Sopenharmony_ci			break;
20362306a36Sopenharmony_ci		case 3:
20462306a36Sopenharmony_ci		default:
20562306a36Sopenharmony_ci			out_pos = 0;
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci		cdev->period_out_count[index] = out_pos;
21062306a36Sopenharmony_ci		cdev->audio_out_buf_pos[index] = out_pos;
21162306a36Sopenharmony_ci	} else {
21262306a36Sopenharmony_ci		int in_pos;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci		switch (cdev->spec.data_alignment) {
21562306a36Sopenharmony_ci		case 0:
21662306a36Sopenharmony_ci			in_pos = BYTES_PER_SAMPLE + 2;
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		case 2:
21962306a36Sopenharmony_ci			in_pos = BYTES_PER_SAMPLE;
22062306a36Sopenharmony_ci			break;
22162306a36Sopenharmony_ci		case 3:
22262306a36Sopenharmony_ci		default:
22362306a36Sopenharmony_ci			in_pos = 0;
22462306a36Sopenharmony_ci			break;
22562306a36Sopenharmony_ci		}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		cdev->period_in_count[index] = in_pos;
22862306a36Sopenharmony_ci		cdev->audio_in_buf_pos[index] = in_pos;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (cdev->streaming)
23262306a36Sopenharmony_ci		return 0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	/* the first client that opens a stream defines the sample rate
23562306a36Sopenharmony_ci	 * setting for all subsequent calls, until the last client closed. */
23662306a36Sopenharmony_ci	for (i=0; i < ARRAY_SIZE(rates); i++)
23762306a36Sopenharmony_ci		if (runtime->rate == rates[i])
23862306a36Sopenharmony_ci			cdev->pcm_info.rates = 1 << i;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	snd_pcm_limit_hw_rates(runtime);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	bytes_per_sample = BYTES_PER_SAMPLE;
24362306a36Sopenharmony_ci	if (cdev->spec.data_alignment >= 2)
24462306a36Sopenharmony_ci		bytes_per_sample++;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	bpp = ((runtime->rate / 8000) + CLOCK_DRIFT_TOLERANCE)
24762306a36Sopenharmony_ci		* bytes_per_sample * CHANNELS_PER_STREAM * cdev->n_streams;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (bpp > MAX_ENDPOINT_SIZE)
25062306a36Sopenharmony_ci		bpp = MAX_ENDPOINT_SIZE;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	ret = snd_usb_caiaq_set_audio_params(cdev, runtime->rate,
25362306a36Sopenharmony_ci					     runtime->sample_bits, bpp);
25462306a36Sopenharmony_ci	if (ret)
25562306a36Sopenharmony_ci		return ret;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	ret = stream_start(cdev);
25862306a36Sopenharmony_ci	if (ret)
25962306a36Sopenharmony_ci		return ret;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	cdev->output_running = 0;
26262306a36Sopenharmony_ci	wait_event_timeout(cdev->prepare_wait_queue, cdev->output_running, HZ);
26362306a36Sopenharmony_ci	if (!cdev->output_running) {
26462306a36Sopenharmony_ci		stream_stop(cdev);
26562306a36Sopenharmony_ci		return -EPIPE;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return 0;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int snd_usb_caiaq_pcm_trigger(struct snd_pcm_substream *sub, int cmd)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
27462306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p) cmd %d\n", __func__, sub, cmd);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	switch (cmd) {
27962306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_START:
28062306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
28162306a36Sopenharmony_ci		activate_substream(cdev, sub);
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_STOP:
28462306a36Sopenharmony_ci	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
28562306a36Sopenharmony_ci		deactivate_substream(cdev, sub);
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci	default:
28862306a36Sopenharmony_ci		return -EINVAL;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return 0;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic snd_pcm_uframes_t
29562306a36Sopenharmony_cisnd_usb_caiaq_pcm_pointer(struct snd_pcm_substream *sub)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	int index = sub->number;
29862306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = snd_pcm_substream_chip(sub);
29962306a36Sopenharmony_ci	snd_pcm_uframes_t ptr;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	spin_lock(&cdev->spinlock);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (cdev->input_panic || cdev->output_panic) {
30462306a36Sopenharmony_ci		ptr = SNDRV_PCM_POS_XRUN;
30562306a36Sopenharmony_ci		goto unlock;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
30962306a36Sopenharmony_ci		ptr = bytes_to_frames(sub->runtime,
31062306a36Sopenharmony_ci					cdev->audio_out_buf_pos[index]);
31162306a36Sopenharmony_ci	else
31262306a36Sopenharmony_ci		ptr = bytes_to_frames(sub->runtime,
31362306a36Sopenharmony_ci					cdev->audio_in_buf_pos[index]);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciunlock:
31662306a36Sopenharmony_ci	spin_unlock(&cdev->spinlock);
31762306a36Sopenharmony_ci	return ptr;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/* operators for both playback and capture */
32162306a36Sopenharmony_cistatic const struct snd_pcm_ops snd_usb_caiaq_ops = {
32262306a36Sopenharmony_ci	.open =		snd_usb_caiaq_substream_open,
32362306a36Sopenharmony_ci	.close =	snd_usb_caiaq_substream_close,
32462306a36Sopenharmony_ci	.hw_free =	snd_usb_caiaq_pcm_hw_free,
32562306a36Sopenharmony_ci	.prepare =	snd_usb_caiaq_pcm_prepare,
32662306a36Sopenharmony_ci	.trigger =	snd_usb_caiaq_pcm_trigger,
32762306a36Sopenharmony_ci	.pointer =	snd_usb_caiaq_pcm_pointer,
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic void check_for_elapsed_periods(struct snd_usb_caiaqdev *cdev,
33162306a36Sopenharmony_ci				      struct snd_pcm_substream **subs)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	int stream, pb, *cnt;
33462306a36Sopenharmony_ci	struct snd_pcm_substream *sub;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	for (stream = 0; stream < cdev->n_streams; stream++) {
33762306a36Sopenharmony_ci		sub = subs[stream];
33862306a36Sopenharmony_ci		if (!sub)
33962306a36Sopenharmony_ci			continue;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		pb = snd_pcm_lib_period_bytes(sub);
34262306a36Sopenharmony_ci		cnt = (sub->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
34362306a36Sopenharmony_ci					&cdev->period_out_count[stream] :
34462306a36Sopenharmony_ci					&cdev->period_in_count[stream];
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci		if (*cnt >= pb) {
34762306a36Sopenharmony_ci			snd_pcm_period_elapsed(sub);
34862306a36Sopenharmony_ci			*cnt %= pb;
34962306a36Sopenharmony_ci		}
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic void read_in_urb_mode0(struct snd_usb_caiaqdev *cdev,
35462306a36Sopenharmony_ci			      const struct urb *urb,
35562306a36Sopenharmony_ci			      const struct usb_iso_packet_descriptor *iso)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
35862306a36Sopenharmony_ci	struct snd_pcm_substream *sub;
35962306a36Sopenharmony_ci	int stream, i;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (all_substreams_zero(cdev->sub_capture))
36262306a36Sopenharmony_ci		return;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	for (i = 0; i < iso->actual_length;) {
36562306a36Sopenharmony_ci		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
36662306a36Sopenharmony_ci			sub = cdev->sub_capture[stream];
36762306a36Sopenharmony_ci			if (sub) {
36862306a36Sopenharmony_ci				struct snd_pcm_runtime *rt = sub->runtime;
36962306a36Sopenharmony_ci				char *audio_buf = rt->dma_area;
37062306a36Sopenharmony_ci				int sz = frames_to_bytes(rt, rt->buffer_size);
37162306a36Sopenharmony_ci				audio_buf[cdev->audio_in_buf_pos[stream]++]
37262306a36Sopenharmony_ci					= usb_buf[i];
37362306a36Sopenharmony_ci				cdev->period_in_count[stream]++;
37462306a36Sopenharmony_ci				if (cdev->audio_in_buf_pos[stream] == sz)
37562306a36Sopenharmony_ci					cdev->audio_in_buf_pos[stream] = 0;
37662306a36Sopenharmony_ci			}
37762306a36Sopenharmony_ci		}
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void read_in_urb_mode2(struct snd_usb_caiaqdev *cdev,
38262306a36Sopenharmony_ci			      const struct urb *urb,
38362306a36Sopenharmony_ci			      const struct usb_iso_packet_descriptor *iso)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
38662306a36Sopenharmony_ci	unsigned char check_byte;
38762306a36Sopenharmony_ci	struct snd_pcm_substream *sub;
38862306a36Sopenharmony_ci	int stream, i;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	for (i = 0; i < iso->actual_length;) {
39162306a36Sopenharmony_ci		if (i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) == 0) {
39262306a36Sopenharmony_ci			for (stream = 0;
39362306a36Sopenharmony_ci			     stream < cdev->n_streams;
39462306a36Sopenharmony_ci			     stream++, i++) {
39562306a36Sopenharmony_ci				if (cdev->first_packet)
39662306a36Sopenharmony_ci					continue;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci				check_byte = MAKE_CHECKBYTE(cdev, stream, i);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci				if ((usb_buf[i] & 0x3f) != check_byte)
40162306a36Sopenharmony_ci					cdev->input_panic = 1;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci				if (usb_buf[i] & 0x80)
40462306a36Sopenharmony_ci					cdev->output_panic = 1;
40562306a36Sopenharmony_ci			}
40662306a36Sopenharmony_ci		}
40762306a36Sopenharmony_ci		cdev->first_packet = 0;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
41062306a36Sopenharmony_ci			sub = cdev->sub_capture[stream];
41162306a36Sopenharmony_ci			if (cdev->input_panic)
41262306a36Sopenharmony_ci				usb_buf[i] = 0;
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci			if (sub) {
41562306a36Sopenharmony_ci				struct snd_pcm_runtime *rt = sub->runtime;
41662306a36Sopenharmony_ci				char *audio_buf = rt->dma_area;
41762306a36Sopenharmony_ci				int sz = frames_to_bytes(rt, rt->buffer_size);
41862306a36Sopenharmony_ci				audio_buf[cdev->audio_in_buf_pos[stream]++] =
41962306a36Sopenharmony_ci					usb_buf[i];
42062306a36Sopenharmony_ci				cdev->period_in_count[stream]++;
42162306a36Sopenharmony_ci				if (cdev->audio_in_buf_pos[stream] == sz)
42262306a36Sopenharmony_ci					cdev->audio_in_buf_pos[stream] = 0;
42362306a36Sopenharmony_ci			}
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic void read_in_urb_mode3(struct snd_usb_caiaqdev *cdev,
42962306a36Sopenharmony_ci			      const struct urb *urb,
43062306a36Sopenharmony_ci			      const struct usb_iso_packet_descriptor *iso)
43162306a36Sopenharmony_ci{
43262306a36Sopenharmony_ci	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
43362306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
43462306a36Sopenharmony_ci	int stream, i;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	/* paranoia check */
43762306a36Sopenharmony_ci	if (iso->actual_length % (BYTES_PER_SAMPLE_USB * CHANNELS_PER_STREAM))
43862306a36Sopenharmony_ci		return;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	for (i = 0; i < iso->actual_length;) {
44162306a36Sopenharmony_ci		for (stream = 0; stream < cdev->n_streams; stream++) {
44262306a36Sopenharmony_ci			struct snd_pcm_substream *sub = cdev->sub_capture[stream];
44362306a36Sopenharmony_ci			char *audio_buf = NULL;
44462306a36Sopenharmony_ci			int c, n, sz = 0;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			if (sub && !cdev->input_panic) {
44762306a36Sopenharmony_ci				struct snd_pcm_runtime *rt = sub->runtime;
44862306a36Sopenharmony_ci				audio_buf = rt->dma_area;
44962306a36Sopenharmony_ci				sz = frames_to_bytes(rt, rt->buffer_size);
45062306a36Sopenharmony_ci			}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci			for (c = 0; c < CHANNELS_PER_STREAM; c++) {
45362306a36Sopenharmony_ci				/* 3 audio data bytes, followed by 1 check byte */
45462306a36Sopenharmony_ci				if (audio_buf) {
45562306a36Sopenharmony_ci					for (n = 0; n < BYTES_PER_SAMPLE; n++) {
45662306a36Sopenharmony_ci						audio_buf[cdev->audio_in_buf_pos[stream]++] = usb_buf[i+n];
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci						if (cdev->audio_in_buf_pos[stream] == sz)
45962306a36Sopenharmony_ci							cdev->audio_in_buf_pos[stream] = 0;
46062306a36Sopenharmony_ci					}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci					cdev->period_in_count[stream] += BYTES_PER_SAMPLE;
46362306a36Sopenharmony_ci				}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci				i += BYTES_PER_SAMPLE;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci				if (usb_buf[i] != ((stream << 1) | c) &&
46862306a36Sopenharmony_ci				    !cdev->first_packet) {
46962306a36Sopenharmony_ci					if (!cdev->input_panic)
47062306a36Sopenharmony_ci						dev_warn(dev, " EXPECTED: %02x got %02x, c %d, stream %d, i %d\n",
47162306a36Sopenharmony_ci							 ((stream << 1) | c), usb_buf[i], c, stream, i);
47262306a36Sopenharmony_ci					cdev->input_panic = 1;
47362306a36Sopenharmony_ci				}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci				i++;
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci		}
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (cdev->first_packet > 0)
48162306a36Sopenharmony_ci		cdev->first_packet--;
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic void read_in_urb(struct snd_usb_caiaqdev *cdev,
48562306a36Sopenharmony_ci			const struct urb *urb,
48662306a36Sopenharmony_ci			const struct usb_iso_packet_descriptor *iso)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (!cdev->streaming)
49162306a36Sopenharmony_ci		return;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	if (iso->actual_length < cdev->bpp)
49462306a36Sopenharmony_ci		return;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	switch (cdev->spec.data_alignment) {
49762306a36Sopenharmony_ci	case 0:
49862306a36Sopenharmony_ci		read_in_urb_mode0(cdev, urb, iso);
49962306a36Sopenharmony_ci		break;
50062306a36Sopenharmony_ci	case 2:
50162306a36Sopenharmony_ci		read_in_urb_mode2(cdev, urb, iso);
50262306a36Sopenharmony_ci		break;
50362306a36Sopenharmony_ci	case 3:
50462306a36Sopenharmony_ci		read_in_urb_mode3(cdev, urb, iso);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if ((cdev->input_panic || cdev->output_panic) && !cdev->warned) {
50962306a36Sopenharmony_ci		dev_warn(dev, "streaming error detected %s %s\n",
51062306a36Sopenharmony_ci				cdev->input_panic ? "(input)" : "",
51162306a36Sopenharmony_ci				cdev->output_panic ? "(output)" : "");
51262306a36Sopenharmony_ci		cdev->warned = 1;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic void fill_out_urb_mode_0(struct snd_usb_caiaqdev *cdev,
51762306a36Sopenharmony_ci				struct urb *urb,
51862306a36Sopenharmony_ci				const struct usb_iso_packet_descriptor *iso)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
52162306a36Sopenharmony_ci	struct snd_pcm_substream *sub;
52262306a36Sopenharmony_ci	int stream, i;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	for (i = 0; i < iso->length;) {
52562306a36Sopenharmony_ci		for (stream = 0; stream < cdev->n_streams; stream++, i++) {
52662306a36Sopenharmony_ci			sub = cdev->sub_playback[stream];
52762306a36Sopenharmony_ci			if (sub) {
52862306a36Sopenharmony_ci				struct snd_pcm_runtime *rt = sub->runtime;
52962306a36Sopenharmony_ci				char *audio_buf = rt->dma_area;
53062306a36Sopenharmony_ci				int sz = frames_to_bytes(rt, rt->buffer_size);
53162306a36Sopenharmony_ci				usb_buf[i] =
53262306a36Sopenharmony_ci					audio_buf[cdev->audio_out_buf_pos[stream]];
53362306a36Sopenharmony_ci				cdev->period_out_count[stream]++;
53462306a36Sopenharmony_ci				cdev->audio_out_buf_pos[stream]++;
53562306a36Sopenharmony_ci				if (cdev->audio_out_buf_pos[stream] == sz)
53662306a36Sopenharmony_ci					cdev->audio_out_buf_pos[stream] = 0;
53762306a36Sopenharmony_ci			} else
53862306a36Sopenharmony_ci				usb_buf[i] = 0;
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci		/* fill in the check bytes */
54262306a36Sopenharmony_ci		if (cdev->spec.data_alignment == 2 &&
54362306a36Sopenharmony_ci		    i % (cdev->n_streams * BYTES_PER_SAMPLE_USB) ==
54462306a36Sopenharmony_ci		        (cdev->n_streams * CHANNELS_PER_STREAM))
54562306a36Sopenharmony_ci			for (stream = 0; stream < cdev->n_streams; stream++, i++)
54662306a36Sopenharmony_ci				usb_buf[i] = MAKE_CHECKBYTE(cdev, stream, i);
54762306a36Sopenharmony_ci	}
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic void fill_out_urb_mode_3(struct snd_usb_caiaqdev *cdev,
55162306a36Sopenharmony_ci				struct urb *urb,
55262306a36Sopenharmony_ci				const struct usb_iso_packet_descriptor *iso)
55362306a36Sopenharmony_ci{
55462306a36Sopenharmony_ci	unsigned char *usb_buf = urb->transfer_buffer + iso->offset;
55562306a36Sopenharmony_ci	int stream, i;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	for (i = 0; i < iso->length;) {
55862306a36Sopenharmony_ci		for (stream = 0; stream < cdev->n_streams; stream++) {
55962306a36Sopenharmony_ci			struct snd_pcm_substream *sub = cdev->sub_playback[stream];
56062306a36Sopenharmony_ci			char *audio_buf = NULL;
56162306a36Sopenharmony_ci			int c, n, sz = 0;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci			if (sub) {
56462306a36Sopenharmony_ci				struct snd_pcm_runtime *rt = sub->runtime;
56562306a36Sopenharmony_ci				audio_buf = rt->dma_area;
56662306a36Sopenharmony_ci				sz = frames_to_bytes(rt, rt->buffer_size);
56762306a36Sopenharmony_ci			}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci			for (c = 0; c < CHANNELS_PER_STREAM; c++) {
57062306a36Sopenharmony_ci				for (n = 0; n < BYTES_PER_SAMPLE; n++) {
57162306a36Sopenharmony_ci					if (audio_buf) {
57262306a36Sopenharmony_ci						usb_buf[i+n] = audio_buf[cdev->audio_out_buf_pos[stream]++];
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci						if (cdev->audio_out_buf_pos[stream] == sz)
57562306a36Sopenharmony_ci							cdev->audio_out_buf_pos[stream] = 0;
57662306a36Sopenharmony_ci					} else {
57762306a36Sopenharmony_ci						usb_buf[i+n] = 0;
57862306a36Sopenharmony_ci					}
57962306a36Sopenharmony_ci				}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci				if (audio_buf)
58262306a36Sopenharmony_ci					cdev->period_out_count[stream] += BYTES_PER_SAMPLE;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci				i += BYTES_PER_SAMPLE;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci				/* fill in the check byte pattern */
58762306a36Sopenharmony_ci				usb_buf[i++] = (stream << 1) | c;
58862306a36Sopenharmony_ci			}
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_cistatic inline void fill_out_urb(struct snd_usb_caiaqdev *cdev,
59462306a36Sopenharmony_ci				struct urb *urb,
59562306a36Sopenharmony_ci				const struct usb_iso_packet_descriptor *iso)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	switch (cdev->spec.data_alignment) {
59862306a36Sopenharmony_ci	case 0:
59962306a36Sopenharmony_ci	case 2:
60062306a36Sopenharmony_ci		fill_out_urb_mode_0(cdev, urb, iso);
60162306a36Sopenharmony_ci		break;
60262306a36Sopenharmony_ci	case 3:
60362306a36Sopenharmony_ci		fill_out_urb_mode_3(cdev, urb, iso);
60462306a36Sopenharmony_ci		break;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_cistatic void read_completed(struct urb *urb)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	struct snd_usb_caiaq_cb_info *info = urb->context;
61162306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev;
61262306a36Sopenharmony_ci	struct device *dev;
61362306a36Sopenharmony_ci	struct urb *out = NULL;
61462306a36Sopenharmony_ci	int i, frame, len, send_it = 0, outframe = 0;
61562306a36Sopenharmony_ci	unsigned long flags;
61662306a36Sopenharmony_ci	size_t offset = 0;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (urb->status || !info)
61962306a36Sopenharmony_ci		return;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	cdev = info->cdev;
62262306a36Sopenharmony_ci	dev = caiaqdev_to_dev(cdev);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (!cdev->streaming)
62562306a36Sopenharmony_ci		return;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* find an unused output urb that is unused */
62862306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++)
62962306a36Sopenharmony_ci		if (test_and_set_bit(i, &cdev->outurb_active_mask) == 0) {
63062306a36Sopenharmony_ci			out = cdev->data_urbs_out[i];
63162306a36Sopenharmony_ci			break;
63262306a36Sopenharmony_ci		}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	if (!out) {
63562306a36Sopenharmony_ci		dev_err(dev, "Unable to find an output urb to use\n");
63662306a36Sopenharmony_ci		goto requeue;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* read the recently received packet and send back one which has
64062306a36Sopenharmony_ci	 * the same layout */
64162306a36Sopenharmony_ci	for (frame = 0; frame < FRAMES_PER_URB; frame++) {
64262306a36Sopenharmony_ci		if (urb->iso_frame_desc[frame].status)
64362306a36Sopenharmony_ci			continue;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		len = urb->iso_frame_desc[outframe].actual_length;
64662306a36Sopenharmony_ci		out->iso_frame_desc[outframe].length = len;
64762306a36Sopenharmony_ci		out->iso_frame_desc[outframe].actual_length = 0;
64862306a36Sopenharmony_ci		out->iso_frame_desc[outframe].offset = offset;
64962306a36Sopenharmony_ci		offset += len;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		if (len > 0) {
65262306a36Sopenharmony_ci			spin_lock_irqsave(&cdev->spinlock, flags);
65362306a36Sopenharmony_ci			fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
65462306a36Sopenharmony_ci			read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
65562306a36Sopenharmony_ci			spin_unlock_irqrestore(&cdev->spinlock, flags);
65662306a36Sopenharmony_ci			check_for_elapsed_periods(cdev, cdev->sub_playback);
65762306a36Sopenharmony_ci			check_for_elapsed_periods(cdev, cdev->sub_capture);
65862306a36Sopenharmony_ci			send_it = 1;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci		outframe++;
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (send_it) {
66562306a36Sopenharmony_ci		out->number_of_packets = outframe;
66662306a36Sopenharmony_ci		usb_submit_urb(out, GFP_ATOMIC);
66762306a36Sopenharmony_ci	} else {
66862306a36Sopenharmony_ci		struct snd_usb_caiaq_cb_info *oinfo = out->context;
66962306a36Sopenharmony_ci		clear_bit(oinfo->index, &cdev->outurb_active_mask);
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cirequeue:
67362306a36Sopenharmony_ci	/* re-submit inbound urb */
67462306a36Sopenharmony_ci	for (frame = 0; frame < FRAMES_PER_URB; frame++) {
67562306a36Sopenharmony_ci		urb->iso_frame_desc[frame].offset = BYTES_PER_FRAME * frame;
67662306a36Sopenharmony_ci		urb->iso_frame_desc[frame].length = BYTES_PER_FRAME;
67762306a36Sopenharmony_ci		urb->iso_frame_desc[frame].actual_length = 0;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	urb->number_of_packets = FRAMES_PER_URB;
68162306a36Sopenharmony_ci	usb_submit_urb(urb, GFP_ATOMIC);
68262306a36Sopenharmony_ci}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cistatic void write_completed(struct urb *urb)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	struct snd_usb_caiaq_cb_info *info = urb->context;
68762306a36Sopenharmony_ci	struct snd_usb_caiaqdev *cdev = info->cdev;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (!cdev->output_running) {
69062306a36Sopenharmony_ci		cdev->output_running = 1;
69162306a36Sopenharmony_ci		wake_up(&cdev->prepare_wait_queue);
69262306a36Sopenharmony_ci	}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	clear_bit(info->index, &cdev->outurb_active_mask);
69562306a36Sopenharmony_ci}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_cistatic struct urb **alloc_urbs(struct snd_usb_caiaqdev *cdev, int dir, int *ret)
69862306a36Sopenharmony_ci{
69962306a36Sopenharmony_ci	int i, frame;
70062306a36Sopenharmony_ci	struct urb **urbs;
70162306a36Sopenharmony_ci	struct usb_device *usb_dev = cdev->chip.dev;
70262306a36Sopenharmony_ci	unsigned int pipe;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	pipe = (dir == SNDRV_PCM_STREAM_PLAYBACK) ?
70562306a36Sopenharmony_ci		usb_sndisocpipe(usb_dev, ENDPOINT_PLAYBACK) :
70662306a36Sopenharmony_ci		usb_rcvisocpipe(usb_dev, ENDPOINT_CAPTURE);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	urbs = kmalloc_array(N_URBS, sizeof(*urbs), GFP_KERNEL);
70962306a36Sopenharmony_ci	if (!urbs) {
71062306a36Sopenharmony_ci		*ret = -ENOMEM;
71162306a36Sopenharmony_ci		return NULL;
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++) {
71562306a36Sopenharmony_ci		urbs[i] = usb_alloc_urb(FRAMES_PER_URB, GFP_KERNEL);
71662306a36Sopenharmony_ci		if (!urbs[i]) {
71762306a36Sopenharmony_ci			*ret = -ENOMEM;
71862306a36Sopenharmony_ci			return urbs;
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		urbs[i]->transfer_buffer =
72262306a36Sopenharmony_ci			kmalloc_array(BYTES_PER_FRAME, FRAMES_PER_URB,
72362306a36Sopenharmony_ci				      GFP_KERNEL);
72462306a36Sopenharmony_ci		if (!urbs[i]->transfer_buffer) {
72562306a36Sopenharmony_ci			*ret = -ENOMEM;
72662306a36Sopenharmony_ci			return urbs;
72762306a36Sopenharmony_ci		}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci		for (frame = 0; frame < FRAMES_PER_URB; frame++) {
73062306a36Sopenharmony_ci			struct usb_iso_packet_descriptor *iso =
73162306a36Sopenharmony_ci				&urbs[i]->iso_frame_desc[frame];
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci			iso->offset = BYTES_PER_FRAME * frame;
73462306a36Sopenharmony_ci			iso->length = BYTES_PER_FRAME;
73562306a36Sopenharmony_ci		}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		urbs[i]->dev = usb_dev;
73862306a36Sopenharmony_ci		urbs[i]->pipe = pipe;
73962306a36Sopenharmony_ci		urbs[i]->transfer_buffer_length = FRAMES_PER_URB
74062306a36Sopenharmony_ci						* BYTES_PER_FRAME;
74162306a36Sopenharmony_ci		urbs[i]->context = &cdev->data_cb_info[i];
74262306a36Sopenharmony_ci		urbs[i]->interval = 1;
74362306a36Sopenharmony_ci		urbs[i]->number_of_packets = FRAMES_PER_URB;
74462306a36Sopenharmony_ci		urbs[i]->complete = (dir == SNDRV_PCM_STREAM_CAPTURE) ?
74562306a36Sopenharmony_ci					read_completed : write_completed;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	*ret = 0;
74962306a36Sopenharmony_ci	return urbs;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic void free_urbs(struct urb **urbs)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	int i;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	if (!urbs)
75762306a36Sopenharmony_ci		return;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++) {
76062306a36Sopenharmony_ci		if (!urbs[i])
76162306a36Sopenharmony_ci			continue;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		usb_kill_urb(urbs[i]);
76462306a36Sopenharmony_ci		kfree(urbs[i]->transfer_buffer);
76562306a36Sopenharmony_ci		usb_free_urb(urbs[i]);
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	kfree(urbs);
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ciint snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	int i, ret;
77462306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	cdev->n_audio_in  = max(cdev->spec.num_analog_audio_in,
77762306a36Sopenharmony_ci			       cdev->spec.num_digital_audio_in) /
77862306a36Sopenharmony_ci				CHANNELS_PER_STREAM;
77962306a36Sopenharmony_ci	cdev->n_audio_out = max(cdev->spec.num_analog_audio_out,
78062306a36Sopenharmony_ci			       cdev->spec.num_digital_audio_out) /
78162306a36Sopenharmony_ci				CHANNELS_PER_STREAM;
78262306a36Sopenharmony_ci	cdev->n_streams = max(cdev->n_audio_in, cdev->n_audio_out);
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	dev_dbg(dev, "cdev->n_audio_in = %d\n", cdev->n_audio_in);
78562306a36Sopenharmony_ci	dev_dbg(dev, "cdev->n_audio_out = %d\n", cdev->n_audio_out);
78662306a36Sopenharmony_ci	dev_dbg(dev, "cdev->n_streams = %d\n", cdev->n_streams);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (cdev->n_streams > MAX_STREAMS) {
78962306a36Sopenharmony_ci		dev_err(dev, "unable to initialize device, too many streams.\n");
79062306a36Sopenharmony_ci		return -EINVAL;
79162306a36Sopenharmony_ci	}
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (cdev->n_streams < 1) {
79462306a36Sopenharmony_ci		dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams);
79562306a36Sopenharmony_ci		return -EINVAL;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	ret = snd_pcm_new(cdev->chip.card, cdev->product_name, 0,
79962306a36Sopenharmony_ci			cdev->n_audio_out, cdev->n_audio_in, &cdev->pcm);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	if (ret < 0) {
80262306a36Sopenharmony_ci		dev_err(dev, "snd_pcm_new() returned %d\n", ret);
80362306a36Sopenharmony_ci		return ret;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	cdev->pcm->private_data = cdev;
80762306a36Sopenharmony_ci	strscpy(cdev->pcm->name, cdev->product_name, sizeof(cdev->pcm->name));
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	memset(cdev->sub_playback, 0, sizeof(cdev->sub_playback));
81062306a36Sopenharmony_ci	memset(cdev->sub_capture, 0, sizeof(cdev->sub_capture));
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	memcpy(&cdev->pcm_info, &snd_usb_caiaq_pcm_hardware,
81362306a36Sopenharmony_ci			sizeof(snd_usb_caiaq_pcm_hardware));
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* setup samplerates */
81662306a36Sopenharmony_ci	cdev->samplerates = cdev->pcm_info.rates;
81762306a36Sopenharmony_ci	switch (cdev->chip.usb_id) {
81862306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1):
81962306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3):
82062306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_SESSIONIO):
82162306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_GUITARRIGMOBILE):
82262306a36Sopenharmony_ci		cdev->samplerates |= SNDRV_PCM_RATE_192000;
82362306a36Sopenharmony_ci		fallthrough;
82462306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO2DJ):
82562306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
82662306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
82762306a36Sopenharmony_ci	case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORAUDIO2):
82862306a36Sopenharmony_ci		cdev->samplerates |= SNDRV_PCM_RATE_88200;
82962306a36Sopenharmony_ci		break;
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_PLAYBACK,
83362306a36Sopenharmony_ci				&snd_usb_caiaq_ops);
83462306a36Sopenharmony_ci	snd_pcm_set_ops(cdev->pcm, SNDRV_PCM_STREAM_CAPTURE,
83562306a36Sopenharmony_ci				&snd_usb_caiaq_ops);
83662306a36Sopenharmony_ci	snd_pcm_set_managed_buffer_all(cdev->pcm, SNDRV_DMA_TYPE_VMALLOC,
83762306a36Sopenharmony_ci				       NULL, 0, 0);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	cdev->data_cb_info =
84062306a36Sopenharmony_ci		kmalloc_array(N_URBS, sizeof(struct snd_usb_caiaq_cb_info),
84162306a36Sopenharmony_ci					GFP_KERNEL);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (!cdev->data_cb_info)
84462306a36Sopenharmony_ci		return -ENOMEM;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	cdev->outurb_active_mask = 0;
84762306a36Sopenharmony_ci	BUILD_BUG_ON(N_URBS > (sizeof(cdev->outurb_active_mask) * 8));
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	for (i = 0; i < N_URBS; i++) {
85062306a36Sopenharmony_ci		cdev->data_cb_info[i].cdev = cdev;
85162306a36Sopenharmony_ci		cdev->data_cb_info[i].index = i;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	cdev->data_urbs_in = alloc_urbs(cdev, SNDRV_PCM_STREAM_CAPTURE, &ret);
85562306a36Sopenharmony_ci	if (ret < 0) {
85662306a36Sopenharmony_ci		kfree(cdev->data_cb_info);
85762306a36Sopenharmony_ci		free_urbs(cdev->data_urbs_in);
85862306a36Sopenharmony_ci		return ret;
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	cdev->data_urbs_out = alloc_urbs(cdev, SNDRV_PCM_STREAM_PLAYBACK, &ret);
86262306a36Sopenharmony_ci	if (ret < 0) {
86362306a36Sopenharmony_ci		kfree(cdev->data_cb_info);
86462306a36Sopenharmony_ci		free_urbs(cdev->data_urbs_in);
86562306a36Sopenharmony_ci		free_urbs(cdev->data_urbs_out);
86662306a36Sopenharmony_ci		return ret;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	return 0;
87062306a36Sopenharmony_ci}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_civoid snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	struct device *dev = caiaqdev_to_dev(cdev);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	dev_dbg(dev, "%s(%p)\n", __func__, cdev);
87762306a36Sopenharmony_ci	stream_stop(cdev);
87862306a36Sopenharmony_ci	free_urbs(cdev->data_urbs_in);
87962306a36Sopenharmony_ci	free_urbs(cdev->data_urbs_out);
88062306a36Sopenharmony_ci	kfree(cdev->data_cb_info);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
883