15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2eb9fecb9SRuslan Bilovol /*
3eb9fecb9SRuslan Bilovol  * u_audio.c -- interface to USB gadget "ALSA sound card" utilities
4eb9fecb9SRuslan Bilovol  *
5eb9fecb9SRuslan Bilovol  * Copyright (C) 2016
6eb9fecb9SRuslan Bilovol  * Author: Ruslan Bilovol <ruslan.bilovol@gmail.com>
7eb9fecb9SRuslan Bilovol  *
8eb9fecb9SRuslan Bilovol  * Sound card implementation was cut-and-pasted with changes
9eb9fecb9SRuslan Bilovol  * from f_uac2.c and has:
10eb9fecb9SRuslan Bilovol  *    Copyright (C) 2011
11eb9fecb9SRuslan Bilovol  *    Yadwinder Singh (yadi.brar01@gmail.com)
12eb9fecb9SRuslan Bilovol  *    Jaswinder Singh (jaswinder.singh@linaro.org)
13eb9fecb9SRuslan Bilovol  */
14eb9fecb9SRuslan Bilovol 
15*02de698cSRuslan Bilovol #include <linux/kernel.h>
16eb9fecb9SRuslan Bilovol #include <linux/module.h>
17eb9fecb9SRuslan Bilovol #include <sound/core.h>
18eb9fecb9SRuslan Bilovol #include <sound/pcm.h>
19eb9fecb9SRuslan Bilovol #include <sound/pcm_params.h>
20e89bb428SRuslan Bilovol #include <sound/control.h>
21*02de698cSRuslan Bilovol #include <sound/tlv.h>
22*02de698cSRuslan Bilovol #include <linux/usb/audio.h>
23eb9fecb9SRuslan Bilovol 
24eb9fecb9SRuslan Bilovol #include "u_audio.h"
25eb9fecb9SRuslan Bilovol 
26eb9fecb9SRuslan Bilovol #define BUFF_SIZE_MAX	(PAGE_SIZE * 16)
27eb9fecb9SRuslan Bilovol #define PRD_SIZE_MAX	PAGE_SIZE
28eb9fecb9SRuslan Bilovol #define MIN_PERIODS	4
29eb9fecb9SRuslan Bilovol 
30*02de698cSRuslan Bilovol enum {
31*02de698cSRuslan Bilovol 	UAC_FBACK_CTRL,
32*02de698cSRuslan Bilovol 	UAC_MUTE_CTRL,
33*02de698cSRuslan Bilovol 	UAC_VOLUME_CTRL,
34*02de698cSRuslan Bilovol };
35*02de698cSRuslan Bilovol 
36eb9fecb9SRuslan Bilovol /* Runtime data params for one stream */
37eb9fecb9SRuslan Bilovol struct uac_rtd_params {
38eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac; /* parent chip */
39eb9fecb9SRuslan Bilovol 	bool ep_enabled; /* if the ep is enabled */
40eb9fecb9SRuslan Bilovol 
41eb9fecb9SRuslan Bilovol 	struct snd_pcm_substream *ss;
42eb9fecb9SRuslan Bilovol 
43eb9fecb9SRuslan Bilovol 	/* Ring buffer */
44eb9fecb9SRuslan Bilovol 	ssize_t hw_ptr;
45eb9fecb9SRuslan Bilovol 
46eb9fecb9SRuslan Bilovol 	void *rbuf;
47eb9fecb9SRuslan Bilovol 
48e89bb428SRuslan Bilovol 	unsigned int pitch;	/* Stream pitch ratio to 1000000 */
49f4408a98SJonas Stenvall 	unsigned int max_psize;	/* MaxPacketSize of endpoint */
50eb9fecb9SRuslan Bilovol 
51d70f7598SJerome Brunet 	struct usb_request **reqs;
5224f779daSRuslan Bilovol 
5324f779daSRuslan Bilovol 	struct usb_request *req_fback; /* Feedback endpoint request */
5424f779daSRuslan Bilovol 	bool fb_ep_enabled; /* if the ep is enabled */
55*02de698cSRuslan Bilovol 
56*02de698cSRuslan Bilovol   /* Volume/Mute controls and their state */
57*02de698cSRuslan Bilovol   int fu_id; /* Feature Unit ID */
58*02de698cSRuslan Bilovol   struct snd_kcontrol *snd_kctl_volume;
59*02de698cSRuslan Bilovol   struct snd_kcontrol *snd_kctl_mute;
60*02de698cSRuslan Bilovol   s16 volume_min, volume_max, volume_res;
61*02de698cSRuslan Bilovol   s16 volume;
62*02de698cSRuslan Bilovol   int mute;
63*02de698cSRuslan Bilovol 
64*02de698cSRuslan Bilovol   spinlock_t lock; /* lock for control transfers */
65*02de698cSRuslan Bilovol 
66eb9fecb9SRuslan Bilovol };
67eb9fecb9SRuslan Bilovol 
68eb9fecb9SRuslan Bilovol struct snd_uac_chip {
69eb9fecb9SRuslan Bilovol 	struct g_audio *audio_dev;
70eb9fecb9SRuslan Bilovol 
71eb9fecb9SRuslan Bilovol 	struct uac_rtd_params p_prm;
72eb9fecb9SRuslan Bilovol 	struct uac_rtd_params c_prm;
73eb9fecb9SRuslan Bilovol 
74eb9fecb9SRuslan Bilovol 	struct snd_card *card;
75eb9fecb9SRuslan Bilovol 	struct snd_pcm *pcm;
76eb9fecb9SRuslan Bilovol 
77eb9fecb9SRuslan Bilovol 	/* timekeeping for the playback endpoint */
78eb9fecb9SRuslan Bilovol 	unsigned int p_interval;
79eb9fecb9SRuslan Bilovol 	unsigned int p_residue;
80eb9fecb9SRuslan Bilovol 
81eb9fecb9SRuslan Bilovol 	/* pre-calculated values for playback iso completion */
82eb9fecb9SRuslan Bilovol 	unsigned int p_pktsize;
83eb9fecb9SRuslan Bilovol 	unsigned int p_pktsize_residue;
84eb9fecb9SRuslan Bilovol 	unsigned int p_framesize;
85eb9fecb9SRuslan Bilovol };
86eb9fecb9SRuslan Bilovol 
872ab3c34cSBhumika Goyal static const struct snd_pcm_hardware uac_pcm_hardware = {
88eb9fecb9SRuslan Bilovol 	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER
89eb9fecb9SRuslan Bilovol 		 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
90eb9fecb9SRuslan Bilovol 		 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
91eb9fecb9SRuslan Bilovol 	.rates = SNDRV_PCM_RATE_CONTINUOUS,
92eb9fecb9SRuslan Bilovol 	.periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX,
93eb9fecb9SRuslan Bilovol 	.buffer_bytes_max = BUFF_SIZE_MAX,
94eb9fecb9SRuslan Bilovol 	.period_bytes_max = PRD_SIZE_MAX,
95eb9fecb9SRuslan Bilovol 	.periods_min = MIN_PERIODS,
96eb9fecb9SRuslan Bilovol };
97eb9fecb9SRuslan Bilovol 
9824f779daSRuslan Bilovol static void u_audio_set_fback_frequency(enum usb_device_speed speed,
99e89bb428SRuslan Bilovol 					unsigned long long freq,
100e89bb428SRuslan Bilovol 					unsigned int pitch,
101e89bb428SRuslan Bilovol 					void *buf)
10224f779daSRuslan Bilovol {
10324f779daSRuslan Bilovol 	u32 ff = 0;
10424f779daSRuslan Bilovol 
105e89bb428SRuslan Bilovol 	/*
106e89bb428SRuslan Bilovol 	 * Because the pitch base is 1000000, the final divider here
107e89bb428SRuslan Bilovol 	 * will be 1000 * 1000000 = 1953125 << 9
108e89bb428SRuslan Bilovol 	 *
109e89bb428SRuslan Bilovol 	 * Instead of dealing with big numbers lets fold this 9 left shift
110e89bb428SRuslan Bilovol 	 */
111e89bb428SRuslan Bilovol 
11224f779daSRuslan Bilovol 	if (speed == USB_SPEED_FULL) {
11324f779daSRuslan Bilovol 		/*
11424f779daSRuslan Bilovol 		 * Full-speed feedback endpoints report frequency
115e89bb428SRuslan Bilovol 		 * in samples/frame
11624f779daSRuslan Bilovol 		 * Format is encoded in Q10.10 left-justified in the 24 bits,
11724f779daSRuslan Bilovol 		 * so that it has a Q10.14 format.
118e89bb428SRuslan Bilovol 		 *
119e89bb428SRuslan Bilovol 		 * ff = (freq << 14) / 1000
12024f779daSRuslan Bilovol 		 */
121e89bb428SRuslan Bilovol 		freq <<= 5;
12224f779daSRuslan Bilovol 	} else {
12324f779daSRuslan Bilovol 		/*
12424f779daSRuslan Bilovol 		 * High-speed feedback endpoints report frequency
12524f779daSRuslan Bilovol 		 * in samples/microframe.
12624f779daSRuslan Bilovol 		 * Format is encoded in Q12.13 fitted into four bytes so that
12724f779daSRuslan Bilovol 		 * the binary point is located between the second and the third
12824f779daSRuslan Bilovol 		 * byte fromat (that is Q16.16)
129e89bb428SRuslan Bilovol 		 *
130e89bb428SRuslan Bilovol 		 * ff = (freq << 16) / 8000
13124f779daSRuslan Bilovol 		 */
132e89bb428SRuslan Bilovol 		freq <<= 4;
13324f779daSRuslan Bilovol 	}
134e89bb428SRuslan Bilovol 
135e89bb428SRuslan Bilovol 	ff = DIV_ROUND_CLOSEST_ULL((freq * pitch), 1953125);
136e89bb428SRuslan Bilovol 
13724f779daSRuslan Bilovol 	*(__le32 *)buf = cpu_to_le32(ff);
13824f779daSRuslan Bilovol }
13924f779daSRuslan Bilovol 
140eb9fecb9SRuslan Bilovol static void u_audio_iso_complete(struct usb_ep *ep, struct usb_request *req)
141eb9fecb9SRuslan Bilovol {
142f4408a98SJonas Stenvall 	unsigned int pending;
143eb9fecb9SRuslan Bilovol 	unsigned int hw_ptr;
144eb9fecb9SRuslan Bilovol 	int status = req->status;
145eb9fecb9SRuslan Bilovol 	struct snd_pcm_substream *substream;
14696afb54eSVladimir Zapolskiy 	struct snd_pcm_runtime *runtime;
14729865117SJerome Brunet 	struct uac_rtd_params *prm = req->context;
148eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
149eb9fecb9SRuslan Bilovol 
150eb9fecb9SRuslan Bilovol 	/* i/f shutting down */
1517de8681bSJack Pham 	if (!prm->ep_enabled) {
1527de8681bSJack Pham 		usb_ep_free_request(ep, req);
1537de8681bSJack Pham 		return;
1547de8681bSJack Pham 	}
1557de8681bSJack Pham 
1567de8681bSJack Pham 	if (req->status == -ESHUTDOWN)
157eb9fecb9SRuslan Bilovol 		return;
158eb9fecb9SRuslan Bilovol 
159eb9fecb9SRuslan Bilovol 	/*
160eb9fecb9SRuslan Bilovol 	 * We can't really do much about bad xfers.
161eb9fecb9SRuslan Bilovol 	 * Afterall, the ISOCH xfers could fail legitimately.
162eb9fecb9SRuslan Bilovol 	 */
163eb9fecb9SRuslan Bilovol 	if (status)
164eb9fecb9SRuslan Bilovol 		pr_debug("%s: iso_complete status(%d) %d/%d\n",
165eb9fecb9SRuslan Bilovol 			__func__, status, req->actual, req->length);
166eb9fecb9SRuslan Bilovol 
167eb9fecb9SRuslan Bilovol 	substream = prm->ss;
168eb9fecb9SRuslan Bilovol 
169eb9fecb9SRuslan Bilovol 	/* Do nothing if ALSA isn't active */
170eb9fecb9SRuslan Bilovol 	if (!substream)
171eb9fecb9SRuslan Bilovol 		goto exit;
172eb9fecb9SRuslan Bilovol 
173d70f7598SJerome Brunet 	snd_pcm_stream_lock(substream);
17456bc6158SVladimir Zapolskiy 
17596afb54eSVladimir Zapolskiy 	runtime = substream->runtime;
17656bc6158SVladimir Zapolskiy 	if (!runtime || !snd_pcm_running(substream)) {
177d70f7598SJerome Brunet 		snd_pcm_stream_unlock(substream);
17856bc6158SVladimir Zapolskiy 		goto exit;
17956bc6158SVladimir Zapolskiy 	}
18056bc6158SVladimir Zapolskiy 
181eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
182eb9fecb9SRuslan Bilovol 		/*
183eb9fecb9SRuslan Bilovol 		 * For each IN packet, take the quotient of the current data
184eb9fecb9SRuslan Bilovol 		 * rate and the endpoint's interval as the base packet size.
185eb9fecb9SRuslan Bilovol 		 * If there is a residue from this division, add it to the
186eb9fecb9SRuslan Bilovol 		 * residue accumulator.
187eb9fecb9SRuslan Bilovol 		 */
188eb9fecb9SRuslan Bilovol 		req->length = uac->p_pktsize;
189eb9fecb9SRuslan Bilovol 		uac->p_residue += uac->p_pktsize_residue;
190eb9fecb9SRuslan Bilovol 
191eb9fecb9SRuslan Bilovol 		/*
192eb9fecb9SRuslan Bilovol 		 * Whenever there are more bytes in the accumulator than we
193eb9fecb9SRuslan Bilovol 		 * need to add one more sample frame, increase this packet's
194eb9fecb9SRuslan Bilovol 		 * size and decrease the accumulator.
195eb9fecb9SRuslan Bilovol 		 */
196eb9fecb9SRuslan Bilovol 		if (uac->p_residue / uac->p_interval >= uac->p_framesize) {
197eb9fecb9SRuslan Bilovol 			req->length += uac->p_framesize;
198eb9fecb9SRuslan Bilovol 			uac->p_residue -= uac->p_framesize *
199eb9fecb9SRuslan Bilovol 					   uac->p_interval;
200eb9fecb9SRuslan Bilovol 		}
201eb9fecb9SRuslan Bilovol 
202eb9fecb9SRuslan Bilovol 		req->actual = req->length;
203eb9fecb9SRuslan Bilovol 	}
204eb9fecb9SRuslan Bilovol 
205eb9fecb9SRuslan Bilovol 	hw_ptr = prm->hw_ptr;
206eb9fecb9SRuslan Bilovol 
207eb9fecb9SRuslan Bilovol 	/* Pack USB load in ALSA ring buffer */
20896afb54eSVladimir Zapolskiy 	pending = runtime->dma_bytes - hw_ptr;
209eb9fecb9SRuslan Bilovol 
210eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
211eb9fecb9SRuslan Bilovol 		if (unlikely(pending < req->actual)) {
21296afb54eSVladimir Zapolskiy 			memcpy(req->buf, runtime->dma_area + hw_ptr, pending);
21396afb54eSVladimir Zapolskiy 			memcpy(req->buf + pending, runtime->dma_area,
214eb9fecb9SRuslan Bilovol 			       req->actual - pending);
215eb9fecb9SRuslan Bilovol 		} else {
21696afb54eSVladimir Zapolskiy 			memcpy(req->buf, runtime->dma_area + hw_ptr,
21796afb54eSVladimir Zapolskiy 			       req->actual);
218eb9fecb9SRuslan Bilovol 		}
219eb9fecb9SRuslan Bilovol 	} else {
220eb9fecb9SRuslan Bilovol 		if (unlikely(pending < req->actual)) {
22196afb54eSVladimir Zapolskiy 			memcpy(runtime->dma_area + hw_ptr, req->buf, pending);
22296afb54eSVladimir Zapolskiy 			memcpy(runtime->dma_area, req->buf + pending,
223eb9fecb9SRuslan Bilovol 			       req->actual - pending);
224eb9fecb9SRuslan Bilovol 		} else {
22596afb54eSVladimir Zapolskiy 			memcpy(runtime->dma_area + hw_ptr, req->buf,
22696afb54eSVladimir Zapolskiy 			       req->actual);
227eb9fecb9SRuslan Bilovol 		}
228eb9fecb9SRuslan Bilovol 	}
229eb9fecb9SRuslan Bilovol 
2306b37bd78SJoshua Frkuska 	/* update hw_ptr after data is copied to memory */
23196afb54eSVladimir Zapolskiy 	prm->hw_ptr = (hw_ptr + req->actual) % runtime->dma_bytes;
232773e53d5SVladimir Zapolskiy 	hw_ptr = prm->hw_ptr;
233d70f7598SJerome Brunet 	snd_pcm_stream_unlock(substream);
2346b37bd78SJoshua Frkuska 
235773e53d5SVladimir Zapolskiy 	if ((hw_ptr % snd_pcm_lib_period_bytes(substream)) < req->actual)
236773e53d5SVladimir Zapolskiy 		snd_pcm_period_elapsed(substream);
237773e53d5SVladimir Zapolskiy 
238eb9fecb9SRuslan Bilovol exit:
239eb9fecb9SRuslan Bilovol 	if (usb_ep_queue(ep, req, GFP_ATOMIC))
240eb9fecb9SRuslan Bilovol 		dev_err(uac->card->dev, "%d Error!\n", __LINE__);
241eb9fecb9SRuslan Bilovol }
242eb9fecb9SRuslan Bilovol 
24324f779daSRuslan Bilovol static void u_audio_iso_fback_complete(struct usb_ep *ep,
24424f779daSRuslan Bilovol 				       struct usb_request *req)
24524f779daSRuslan Bilovol {
24624f779daSRuslan Bilovol 	struct uac_rtd_params *prm = req->context;
24724f779daSRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
24824f779daSRuslan Bilovol 	struct g_audio *audio_dev = uac->audio_dev;
249e89bb428SRuslan Bilovol 	struct uac_params *params = &audio_dev->params;
25024f779daSRuslan Bilovol 	int status = req->status;
25124f779daSRuslan Bilovol 
25224f779daSRuslan Bilovol 	/* i/f shutting down */
25324f779daSRuslan Bilovol 	if (!prm->fb_ep_enabled || req->status == -ESHUTDOWN)
25424f779daSRuslan Bilovol 		return;
25524f779daSRuslan Bilovol 
25624f779daSRuslan Bilovol 	/*
25724f779daSRuslan Bilovol 	 * We can't really do much about bad xfers.
25824f779daSRuslan Bilovol 	 * Afterall, the ISOCH xfers could fail legitimately.
25924f779daSRuslan Bilovol 	 */
26024f779daSRuslan Bilovol 	if (status)
26124f779daSRuslan Bilovol 		pr_debug("%s: iso_complete status(%d) %d/%d\n",
26224f779daSRuslan Bilovol 			__func__, status, req->actual, req->length);
26324f779daSRuslan Bilovol 
26424f779daSRuslan Bilovol 	u_audio_set_fback_frequency(audio_dev->gadget->speed,
265e89bb428SRuslan Bilovol 				    params->c_srate, prm->pitch,
266e89bb428SRuslan Bilovol 				    req->buf);
26724f779daSRuslan Bilovol 
26824f779daSRuslan Bilovol 	if (usb_ep_queue(ep, req, GFP_ATOMIC))
26924f779daSRuslan Bilovol 		dev_err(uac->card->dev, "%d Error!\n", __LINE__);
27024f779daSRuslan Bilovol }
27124f779daSRuslan Bilovol 
272eb9fecb9SRuslan Bilovol static int uac_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
273eb9fecb9SRuslan Bilovol {
274eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
275eb9fecb9SRuslan Bilovol 	struct uac_rtd_params *prm;
276eb9fecb9SRuslan Bilovol 	struct g_audio *audio_dev;
277eb9fecb9SRuslan Bilovol 	struct uac_params *params;
278eb9fecb9SRuslan Bilovol 	int err = 0;
279eb9fecb9SRuslan Bilovol 
280eb9fecb9SRuslan Bilovol 	audio_dev = uac->audio_dev;
281eb9fecb9SRuslan Bilovol 	params = &audio_dev->params;
282eb9fecb9SRuslan Bilovol 
283eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
284eb9fecb9SRuslan Bilovol 		prm = &uac->p_prm;
285eb9fecb9SRuslan Bilovol 	else
286eb9fecb9SRuslan Bilovol 		prm = &uac->c_prm;
287eb9fecb9SRuslan Bilovol 
288eb9fecb9SRuslan Bilovol 	/* Reset */
289eb9fecb9SRuslan Bilovol 	prm->hw_ptr = 0;
290eb9fecb9SRuslan Bilovol 
291eb9fecb9SRuslan Bilovol 	switch (cmd) {
292eb9fecb9SRuslan Bilovol 	case SNDRV_PCM_TRIGGER_START:
293eb9fecb9SRuslan Bilovol 	case SNDRV_PCM_TRIGGER_RESUME:
294eb9fecb9SRuslan Bilovol 		prm->ss = substream;
295eb9fecb9SRuslan Bilovol 		break;
296eb9fecb9SRuslan Bilovol 	case SNDRV_PCM_TRIGGER_STOP:
297eb9fecb9SRuslan Bilovol 	case SNDRV_PCM_TRIGGER_SUSPEND:
298eb9fecb9SRuslan Bilovol 		prm->ss = NULL;
299eb9fecb9SRuslan Bilovol 		break;
300eb9fecb9SRuslan Bilovol 	default:
301eb9fecb9SRuslan Bilovol 		err = -EINVAL;
302eb9fecb9SRuslan Bilovol 	}
303eb9fecb9SRuslan Bilovol 
304eb9fecb9SRuslan Bilovol 	/* Clear buffer after Play stops */
305eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss)
306eb9fecb9SRuslan Bilovol 		memset(prm->rbuf, 0, prm->max_psize * params->req_number);
307eb9fecb9SRuslan Bilovol 
308eb9fecb9SRuslan Bilovol 	return err;
309eb9fecb9SRuslan Bilovol }
310eb9fecb9SRuslan Bilovol 
311eb9fecb9SRuslan Bilovol static snd_pcm_uframes_t uac_pcm_pointer(struct snd_pcm_substream *substream)
312eb9fecb9SRuslan Bilovol {
313eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
314eb9fecb9SRuslan Bilovol 	struct uac_rtd_params *prm;
315eb9fecb9SRuslan Bilovol 
316eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
317eb9fecb9SRuslan Bilovol 		prm = &uac->p_prm;
318eb9fecb9SRuslan Bilovol 	else
319eb9fecb9SRuslan Bilovol 		prm = &uac->c_prm;
320eb9fecb9SRuslan Bilovol 
321eb9fecb9SRuslan Bilovol 	return bytes_to_frames(substream->runtime, prm->hw_ptr);
322eb9fecb9SRuslan Bilovol }
323eb9fecb9SRuslan Bilovol 
32425dbd75dSJerome Brunet static u64 uac_ssize_to_fmt(int ssize)
32525dbd75dSJerome Brunet {
32625dbd75dSJerome Brunet 	u64 ret;
32725dbd75dSJerome Brunet 
32825dbd75dSJerome Brunet 	switch (ssize) {
32925dbd75dSJerome Brunet 	case 3:
33025dbd75dSJerome Brunet 		ret = SNDRV_PCM_FMTBIT_S24_3LE;
33125dbd75dSJerome Brunet 		break;
33225dbd75dSJerome Brunet 	case 4:
33325dbd75dSJerome Brunet 		ret = SNDRV_PCM_FMTBIT_S32_LE;
33425dbd75dSJerome Brunet 		break;
33525dbd75dSJerome Brunet 	default:
33625dbd75dSJerome Brunet 		ret = SNDRV_PCM_FMTBIT_S16_LE;
33725dbd75dSJerome Brunet 		break;
33825dbd75dSJerome Brunet 	}
33925dbd75dSJerome Brunet 
34025dbd75dSJerome Brunet 	return ret;
34125dbd75dSJerome Brunet }
34225dbd75dSJerome Brunet 
343eb9fecb9SRuslan Bilovol static int uac_pcm_open(struct snd_pcm_substream *substream)
344eb9fecb9SRuslan Bilovol {
345eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = snd_pcm_substream_chip(substream);
346eb9fecb9SRuslan Bilovol 	struct snd_pcm_runtime *runtime = substream->runtime;
347eb9fecb9SRuslan Bilovol 	struct g_audio *audio_dev;
348eb9fecb9SRuslan Bilovol 	struct uac_params *params;
349eb9fecb9SRuslan Bilovol 	int p_ssize, c_ssize;
350eb9fecb9SRuslan Bilovol 	int p_srate, c_srate;
351eb9fecb9SRuslan Bilovol 	int p_chmask, c_chmask;
352eb9fecb9SRuslan Bilovol 
353eb9fecb9SRuslan Bilovol 	audio_dev = uac->audio_dev;
354eb9fecb9SRuslan Bilovol 	params = &audio_dev->params;
355eb9fecb9SRuslan Bilovol 	p_ssize = params->p_ssize;
356eb9fecb9SRuslan Bilovol 	c_ssize = params->c_ssize;
357eb9fecb9SRuslan Bilovol 	p_srate = params->p_srate;
358eb9fecb9SRuslan Bilovol 	c_srate = params->c_srate;
359eb9fecb9SRuslan Bilovol 	p_chmask = params->p_chmask;
360eb9fecb9SRuslan Bilovol 	c_chmask = params->c_chmask;
361eb9fecb9SRuslan Bilovol 	uac->p_residue = 0;
362eb9fecb9SRuslan Bilovol 
363eb9fecb9SRuslan Bilovol 	runtime->hw = uac_pcm_hardware;
364eb9fecb9SRuslan Bilovol 
365eb9fecb9SRuslan Bilovol 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
366eb9fecb9SRuslan Bilovol 		runtime->hw.rate_min = p_srate;
36725dbd75dSJerome Brunet 		runtime->hw.formats = uac_ssize_to_fmt(p_ssize);
368eb9fecb9SRuslan Bilovol 		runtime->hw.channels_min = num_channels(p_chmask);
369eb9fecb9SRuslan Bilovol 		runtime->hw.period_bytes_min = 2 * uac->p_prm.max_psize
370eb9fecb9SRuslan Bilovol 						/ runtime->hw.periods_min;
371eb9fecb9SRuslan Bilovol 	} else {
372eb9fecb9SRuslan Bilovol 		runtime->hw.rate_min = c_srate;
37325dbd75dSJerome Brunet 		runtime->hw.formats = uac_ssize_to_fmt(c_ssize);
374eb9fecb9SRuslan Bilovol 		runtime->hw.channels_min = num_channels(c_chmask);
375eb9fecb9SRuslan Bilovol 		runtime->hw.period_bytes_min = 2 * uac->c_prm.max_psize
376eb9fecb9SRuslan Bilovol 						/ runtime->hw.periods_min;
377eb9fecb9SRuslan Bilovol 	}
378eb9fecb9SRuslan Bilovol 
379eb9fecb9SRuslan Bilovol 	runtime->hw.rate_max = runtime->hw.rate_min;
380eb9fecb9SRuslan Bilovol 	runtime->hw.channels_max = runtime->hw.channels_min;
381eb9fecb9SRuslan Bilovol 
382eb9fecb9SRuslan Bilovol 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
383eb9fecb9SRuslan Bilovol 
384eb9fecb9SRuslan Bilovol 	return 0;
385eb9fecb9SRuslan Bilovol }
386eb9fecb9SRuslan Bilovol 
387eb9fecb9SRuslan Bilovol /* ALSA cries without these function pointers */
388eb9fecb9SRuslan Bilovol static int uac_pcm_null(struct snd_pcm_substream *substream)
389eb9fecb9SRuslan Bilovol {
390eb9fecb9SRuslan Bilovol 	return 0;
391eb9fecb9SRuslan Bilovol }
392eb9fecb9SRuslan Bilovol 
393640c0be8SArvind Yadav static const struct snd_pcm_ops uac_pcm_ops = {
394eb9fecb9SRuslan Bilovol 	.open = uac_pcm_open,
395eb9fecb9SRuslan Bilovol 	.close = uac_pcm_null,
396eb9fecb9SRuslan Bilovol 	.trigger = uac_pcm_trigger,
397eb9fecb9SRuslan Bilovol 	.pointer = uac_pcm_pointer,
398eb9fecb9SRuslan Bilovol 	.prepare = uac_pcm_null,
399eb9fecb9SRuslan Bilovol };
400eb9fecb9SRuslan Bilovol 
401eb9fecb9SRuslan Bilovol static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep)
402eb9fecb9SRuslan Bilovol {
403eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
404eb9fecb9SRuslan Bilovol 	struct g_audio *audio_dev;
405eb9fecb9SRuslan Bilovol 	struct uac_params *params;
406eb9fecb9SRuslan Bilovol 	int i;
407eb9fecb9SRuslan Bilovol 
408eb9fecb9SRuslan Bilovol 	if (!prm->ep_enabled)
409eb9fecb9SRuslan Bilovol 		return;
410eb9fecb9SRuslan Bilovol 
411eb9fecb9SRuslan Bilovol 	prm->ep_enabled = false;
412eb9fecb9SRuslan Bilovol 
413eb9fecb9SRuslan Bilovol 	audio_dev = uac->audio_dev;
414eb9fecb9SRuslan Bilovol 	params = &audio_dev->params;
415eb9fecb9SRuslan Bilovol 
416eb9fecb9SRuslan Bilovol 	for (i = 0; i < params->req_number; i++) {
41729865117SJerome Brunet 		if (prm->reqs[i]) {
41829865117SJerome Brunet 			if (usb_ep_dequeue(ep, prm->reqs[i]))
41929865117SJerome Brunet 				usb_ep_free_request(ep, prm->reqs[i]);
4207de8681bSJack Pham 			/*
4217de8681bSJack Pham 			 * If usb_ep_dequeue() cannot successfully dequeue the
4227de8681bSJack Pham 			 * request, the request will be freed by the completion
4237de8681bSJack Pham 			 * callback.
4247de8681bSJack Pham 			 */
4257de8681bSJack Pham 
42629865117SJerome Brunet 			prm->reqs[i] = NULL;
427eb9fecb9SRuslan Bilovol 		}
428eb9fecb9SRuslan Bilovol 	}
429eb9fecb9SRuslan Bilovol 
430eb9fecb9SRuslan Bilovol 	if (usb_ep_disable(ep))
431eb9fecb9SRuslan Bilovol 		dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
432eb9fecb9SRuslan Bilovol }
433eb9fecb9SRuslan Bilovol 
43424f779daSRuslan Bilovol static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep)
43524f779daSRuslan Bilovol {
43624f779daSRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
43724f779daSRuslan Bilovol 
43824f779daSRuslan Bilovol 	if (!prm->fb_ep_enabled)
43924f779daSRuslan Bilovol 		return;
44024f779daSRuslan Bilovol 
44124f779daSRuslan Bilovol 	prm->fb_ep_enabled = false;
44224f779daSRuslan Bilovol 
44324f779daSRuslan Bilovol 	if (prm->req_fback) {
44424f779daSRuslan Bilovol 		usb_ep_dequeue(ep, prm->req_fback);
44524f779daSRuslan Bilovol 		kfree(prm->req_fback->buf);
44624f779daSRuslan Bilovol 		usb_ep_free_request(ep, prm->req_fback);
44724f779daSRuslan Bilovol 		prm->req_fback = NULL;
44824f779daSRuslan Bilovol 	}
44924f779daSRuslan Bilovol 
45024f779daSRuslan Bilovol 	if (usb_ep_disable(ep))
45124f779daSRuslan Bilovol 		dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__);
45224f779daSRuslan Bilovol }
453eb9fecb9SRuslan Bilovol 
454eb9fecb9SRuslan Bilovol int u_audio_start_capture(struct g_audio *audio_dev)
455eb9fecb9SRuslan Bilovol {
456eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
457eb9fecb9SRuslan Bilovol 	struct usb_gadget *gadget = audio_dev->gadget;
458eb9fecb9SRuslan Bilovol 	struct device *dev = &gadget->dev;
45924f779daSRuslan Bilovol 	struct usb_request *req, *req_fback;
46024f779daSRuslan Bilovol 	struct usb_ep *ep, *ep_fback;
461eb9fecb9SRuslan Bilovol 	struct uac_rtd_params *prm;
462eb9fecb9SRuslan Bilovol 	struct uac_params *params = &audio_dev->params;
463eb9fecb9SRuslan Bilovol 	int req_len, i;
464eb9fecb9SRuslan Bilovol 
465eb9fecb9SRuslan Bilovol 	ep = audio_dev->out_ep;
466eb9fecb9SRuslan Bilovol 	prm = &uac->c_prm;
467eb9fecb9SRuslan Bilovol 	config_ep_by_speed(gadget, &audio_dev->func, ep);
468904967c6SJohn Keeping 	req_len = ep->maxpacket;
469eb9fecb9SRuslan Bilovol 
470eb9fecb9SRuslan Bilovol 	prm->ep_enabled = true;
471eb9fecb9SRuslan Bilovol 	usb_ep_enable(ep);
472eb9fecb9SRuslan Bilovol 
473eb9fecb9SRuslan Bilovol 	for (i = 0; i < params->req_number; i++) {
47429865117SJerome Brunet 		if (!prm->reqs[i]) {
475eb9fecb9SRuslan Bilovol 			req = usb_ep_alloc_request(ep, GFP_ATOMIC);
476eb9fecb9SRuslan Bilovol 			if (req == NULL)
477eb9fecb9SRuslan Bilovol 				return -ENOMEM;
478eb9fecb9SRuslan Bilovol 
47929865117SJerome Brunet 			prm->reqs[i] = req;
480eb9fecb9SRuslan Bilovol 
481eb9fecb9SRuslan Bilovol 			req->zero = 0;
48229865117SJerome Brunet 			req->context = prm;
483eb9fecb9SRuslan Bilovol 			req->length = req_len;
484eb9fecb9SRuslan Bilovol 			req->complete = u_audio_iso_complete;
485904967c6SJohn Keeping 			req->buf = prm->rbuf + i * ep->maxpacket;
486eb9fecb9SRuslan Bilovol 		}
487eb9fecb9SRuslan Bilovol 
48829865117SJerome Brunet 		if (usb_ep_queue(ep, prm->reqs[i], GFP_ATOMIC))
489eb9fecb9SRuslan Bilovol 			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
490eb9fecb9SRuslan Bilovol 	}
491eb9fecb9SRuslan Bilovol 
49224f779daSRuslan Bilovol 	ep_fback = audio_dev->in_ep_fback;
49324f779daSRuslan Bilovol 	if (!ep_fback)
49424f779daSRuslan Bilovol 		return 0;
49524f779daSRuslan Bilovol 
49624f779daSRuslan Bilovol 	/* Setup feedback endpoint */
49724f779daSRuslan Bilovol 	config_ep_by_speed(gadget, &audio_dev->func, ep_fback);
49824f779daSRuslan Bilovol 	prm->fb_ep_enabled = true;
49924f779daSRuslan Bilovol 	usb_ep_enable(ep_fback);
50024f779daSRuslan Bilovol 	req_len = ep_fback->maxpacket;
50124f779daSRuslan Bilovol 
50224f779daSRuslan Bilovol 	req_fback = usb_ep_alloc_request(ep_fback, GFP_ATOMIC);
50324f779daSRuslan Bilovol 	if (req_fback == NULL)
50424f779daSRuslan Bilovol 		return -ENOMEM;
50524f779daSRuslan Bilovol 
50624f779daSRuslan Bilovol 	prm->req_fback = req_fback;
50724f779daSRuslan Bilovol 	req_fback->zero = 0;
50824f779daSRuslan Bilovol 	req_fback->context = prm;
50924f779daSRuslan Bilovol 	req_fback->length = req_len;
51024f779daSRuslan Bilovol 	req_fback->complete = u_audio_iso_fback_complete;
51124f779daSRuslan Bilovol 
51224f779daSRuslan Bilovol 	req_fback->buf = kzalloc(req_len, GFP_ATOMIC);
51324f779daSRuslan Bilovol 	if (!req_fback->buf)
51424f779daSRuslan Bilovol 		return -ENOMEM;
51524f779daSRuslan Bilovol 
51624f779daSRuslan Bilovol 	/*
51724f779daSRuslan Bilovol 	 * Configure the feedback endpoint's reported frequency.
51824f779daSRuslan Bilovol 	 * Always start with original frequency since its deviation can't
51924f779daSRuslan Bilovol 	 * be meauserd at start of playback
52024f779daSRuslan Bilovol 	 */
521e89bb428SRuslan Bilovol 	prm->pitch = 1000000;
52224f779daSRuslan Bilovol 	u_audio_set_fback_frequency(audio_dev->gadget->speed,
523e89bb428SRuslan Bilovol 				    params->c_srate, prm->pitch,
524e89bb428SRuslan Bilovol 				    req_fback->buf);
52524f779daSRuslan Bilovol 
52624f779daSRuslan Bilovol 	if (usb_ep_queue(ep_fback, req_fback, GFP_ATOMIC))
52724f779daSRuslan Bilovol 		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
52824f779daSRuslan Bilovol 
529eb9fecb9SRuslan Bilovol 	return 0;
530eb9fecb9SRuslan Bilovol }
531eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_start_capture);
532eb9fecb9SRuslan Bilovol 
533eb9fecb9SRuslan Bilovol void u_audio_stop_capture(struct g_audio *audio_dev)
534eb9fecb9SRuslan Bilovol {
535eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
536eb9fecb9SRuslan Bilovol 
53724f779daSRuslan Bilovol 	if (audio_dev->in_ep_fback)
53824f779daSRuslan Bilovol 		free_ep_fback(&uac->c_prm, audio_dev->in_ep_fback);
539eb9fecb9SRuslan Bilovol 	free_ep(&uac->c_prm, audio_dev->out_ep);
540eb9fecb9SRuslan Bilovol }
541eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_stop_capture);
542eb9fecb9SRuslan Bilovol 
543eb9fecb9SRuslan Bilovol int u_audio_start_playback(struct g_audio *audio_dev)
544eb9fecb9SRuslan Bilovol {
545eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
546eb9fecb9SRuslan Bilovol 	struct usb_gadget *gadget = audio_dev->gadget;
547eb9fecb9SRuslan Bilovol 	struct device *dev = &gadget->dev;
548eb9fecb9SRuslan Bilovol 	struct usb_request *req;
549eb9fecb9SRuslan Bilovol 	struct usb_ep *ep;
550eb9fecb9SRuslan Bilovol 	struct uac_rtd_params *prm;
551eb9fecb9SRuslan Bilovol 	struct uac_params *params = &audio_dev->params;
5526b02af34SJohn Keeping 	unsigned int factor;
553eb9fecb9SRuslan Bilovol 	const struct usb_endpoint_descriptor *ep_desc;
554eb9fecb9SRuslan Bilovol 	int req_len, i;
555eb9fecb9SRuslan Bilovol 
556eb9fecb9SRuslan Bilovol 	ep = audio_dev->in_ep;
557eb9fecb9SRuslan Bilovol 	prm = &uac->p_prm;
558eb9fecb9SRuslan Bilovol 	config_ep_by_speed(gadget, &audio_dev->func, ep);
559eb9fecb9SRuslan Bilovol 
560eb9fecb9SRuslan Bilovol 	ep_desc = ep->desc;
561eb9fecb9SRuslan Bilovol 
562eb9fecb9SRuslan Bilovol 	/* pre-calculate the playback endpoint's interval */
563eb9fecb9SRuslan Bilovol 	if (gadget->speed == USB_SPEED_FULL)
564eb9fecb9SRuslan Bilovol 		factor = 1000;
565eb9fecb9SRuslan Bilovol 	else
566eb9fecb9SRuslan Bilovol 		factor = 8000;
567eb9fecb9SRuslan Bilovol 
568eb9fecb9SRuslan Bilovol 	/* pre-compute some values for iso_complete() */
569eb9fecb9SRuslan Bilovol 	uac->p_framesize = params->p_ssize *
570eb9fecb9SRuslan Bilovol 			    num_channels(params->p_chmask);
571eb9fecb9SRuslan Bilovol 	uac->p_interval = factor / (1 << (ep_desc->bInterval - 1));
5726b02af34SJohn Keeping 	uac->p_pktsize = min_t(unsigned int,
5736b02af34SJohn Keeping 				uac->p_framesize *
5746b02af34SJohn Keeping 					(params->p_srate / uac->p_interval),
575904967c6SJohn Keeping 				ep->maxpacket);
576eb9fecb9SRuslan Bilovol 
577904967c6SJohn Keeping 	if (uac->p_pktsize < ep->maxpacket)
5786b02af34SJohn Keeping 		uac->p_pktsize_residue = uac->p_framesize *
5796b02af34SJohn Keeping 			(params->p_srate % uac->p_interval);
580eb9fecb9SRuslan Bilovol 	else
581eb9fecb9SRuslan Bilovol 		uac->p_pktsize_residue = 0;
582eb9fecb9SRuslan Bilovol 
583eb9fecb9SRuslan Bilovol 	req_len = uac->p_pktsize;
584eb9fecb9SRuslan Bilovol 	uac->p_residue = 0;
585eb9fecb9SRuslan Bilovol 
586eb9fecb9SRuslan Bilovol 	prm->ep_enabled = true;
587eb9fecb9SRuslan Bilovol 	usb_ep_enable(ep);
588eb9fecb9SRuslan Bilovol 
589eb9fecb9SRuslan Bilovol 	for (i = 0; i < params->req_number; i++) {
59029865117SJerome Brunet 		if (!prm->reqs[i]) {
591eb9fecb9SRuslan Bilovol 			req = usb_ep_alloc_request(ep, GFP_ATOMIC);
592eb9fecb9SRuslan Bilovol 			if (req == NULL)
593eb9fecb9SRuslan Bilovol 				return -ENOMEM;
594eb9fecb9SRuslan Bilovol 
59529865117SJerome Brunet 			prm->reqs[i] = req;
596eb9fecb9SRuslan Bilovol 
597eb9fecb9SRuslan Bilovol 			req->zero = 0;
59829865117SJerome Brunet 			req->context = prm;
599eb9fecb9SRuslan Bilovol 			req->length = req_len;
600eb9fecb9SRuslan Bilovol 			req->complete = u_audio_iso_complete;
601904967c6SJohn Keeping 			req->buf = prm->rbuf + i * ep->maxpacket;
602eb9fecb9SRuslan Bilovol 		}
603eb9fecb9SRuslan Bilovol 
60429865117SJerome Brunet 		if (usb_ep_queue(ep, prm->reqs[i], GFP_ATOMIC))
605eb9fecb9SRuslan Bilovol 			dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
606eb9fecb9SRuslan Bilovol 	}
607eb9fecb9SRuslan Bilovol 
608eb9fecb9SRuslan Bilovol 	return 0;
609eb9fecb9SRuslan Bilovol }
610eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_start_playback);
611eb9fecb9SRuslan Bilovol 
612eb9fecb9SRuslan Bilovol void u_audio_stop_playback(struct g_audio *audio_dev)
613eb9fecb9SRuslan Bilovol {
614eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
615eb9fecb9SRuslan Bilovol 
616eb9fecb9SRuslan Bilovol 	free_ep(&uac->p_prm, audio_dev->in_ep);
617eb9fecb9SRuslan Bilovol }
618eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_stop_playback);
619eb9fecb9SRuslan Bilovol 
620*02de698cSRuslan Bilovol int u_audio_get_volume(struct g_audio *audio_dev, int playback, s16 *val)
621*02de698cSRuslan Bilovol {
622*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
623*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm;
624*02de698cSRuslan Bilovol 	unsigned long flags;
625*02de698cSRuslan Bilovol 
626*02de698cSRuslan Bilovol 	if (playback)
627*02de698cSRuslan Bilovol 		prm = &uac->p_prm;
628*02de698cSRuslan Bilovol 	else
629*02de698cSRuslan Bilovol 		prm = &uac->c_prm;
630*02de698cSRuslan Bilovol 
631*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
632*02de698cSRuslan Bilovol 	*val = prm->volume;
633*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
634*02de698cSRuslan Bilovol 
635*02de698cSRuslan Bilovol 	return 0;
636*02de698cSRuslan Bilovol }
637*02de698cSRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_get_volume);
638*02de698cSRuslan Bilovol 
639*02de698cSRuslan Bilovol int u_audio_set_volume(struct g_audio *audio_dev, int playback, s16 val)
640*02de698cSRuslan Bilovol {
641*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
642*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm;
643*02de698cSRuslan Bilovol 	unsigned long flags;
644*02de698cSRuslan Bilovol 	int change = 0;
645*02de698cSRuslan Bilovol 
646*02de698cSRuslan Bilovol 	if (playback)
647*02de698cSRuslan Bilovol 		prm = &uac->p_prm;
648*02de698cSRuslan Bilovol 	else
649*02de698cSRuslan Bilovol 		prm = &uac->c_prm;
650*02de698cSRuslan Bilovol 
651*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
652*02de698cSRuslan Bilovol 	val = clamp(val, prm->volume_min, prm->volume_max);
653*02de698cSRuslan Bilovol 	if (prm->volume != val) {
654*02de698cSRuslan Bilovol 		prm->volume = val;
655*02de698cSRuslan Bilovol 		change = 1;
656*02de698cSRuslan Bilovol 	}
657*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
658*02de698cSRuslan Bilovol 
659*02de698cSRuslan Bilovol 	if (change)
660*02de698cSRuslan Bilovol 		snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
661*02de698cSRuslan Bilovol 				&prm->snd_kctl_volume->id);
662*02de698cSRuslan Bilovol 
663*02de698cSRuslan Bilovol 	return 0;
664*02de698cSRuslan Bilovol }
665*02de698cSRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_set_volume);
666*02de698cSRuslan Bilovol 
667*02de698cSRuslan Bilovol int u_audio_get_mute(struct g_audio *audio_dev, int playback, int *val)
668*02de698cSRuslan Bilovol {
669*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
670*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm;
671*02de698cSRuslan Bilovol 	unsigned long flags;
672*02de698cSRuslan Bilovol 
673*02de698cSRuslan Bilovol 	if (playback)
674*02de698cSRuslan Bilovol 		prm = &uac->p_prm;
675*02de698cSRuslan Bilovol 	else
676*02de698cSRuslan Bilovol 		prm = &uac->c_prm;
677*02de698cSRuslan Bilovol 
678*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
679*02de698cSRuslan Bilovol 	*val = prm->mute;
680*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
681*02de698cSRuslan Bilovol 
682*02de698cSRuslan Bilovol 	return 0;
683*02de698cSRuslan Bilovol }
684*02de698cSRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_get_mute);
685*02de698cSRuslan Bilovol 
686*02de698cSRuslan Bilovol int u_audio_set_mute(struct g_audio *audio_dev, int playback, int val)
687*02de698cSRuslan Bilovol {
688*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = audio_dev->uac;
689*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm;
690*02de698cSRuslan Bilovol 	unsigned long flags;
691*02de698cSRuslan Bilovol 	int change = 0;
692*02de698cSRuslan Bilovol 	int mute;
693*02de698cSRuslan Bilovol 
694*02de698cSRuslan Bilovol 	if (playback)
695*02de698cSRuslan Bilovol 		prm = &uac->p_prm;
696*02de698cSRuslan Bilovol 	else
697*02de698cSRuslan Bilovol 		prm = &uac->c_prm;
698*02de698cSRuslan Bilovol 
699*02de698cSRuslan Bilovol 	mute = val ? 1 : 0;
700*02de698cSRuslan Bilovol 
701*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
702*02de698cSRuslan Bilovol 	if (prm->mute != mute) {
703*02de698cSRuslan Bilovol 		prm->mute = mute;
704*02de698cSRuslan Bilovol 		change = 1;
705*02de698cSRuslan Bilovol 	}
706*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
707*02de698cSRuslan Bilovol 
708*02de698cSRuslan Bilovol 	if (change)
709*02de698cSRuslan Bilovol 		snd_ctl_notify(uac->card, SNDRV_CTL_EVENT_MASK_VALUE,
710*02de698cSRuslan Bilovol 			       &prm->snd_kctl_mute->id);
711*02de698cSRuslan Bilovol 
712*02de698cSRuslan Bilovol 	return 0;
713*02de698cSRuslan Bilovol }
714*02de698cSRuslan Bilovol EXPORT_SYMBOL_GPL(u_audio_set_mute);
715*02de698cSRuslan Bilovol 
716*02de698cSRuslan Bilovol 
717e89bb428SRuslan Bilovol static int u_audio_pitch_info(struct snd_kcontrol *kcontrol,
718e89bb428SRuslan Bilovol 				   struct snd_ctl_elem_info *uinfo)
719e89bb428SRuslan Bilovol {
720e89bb428SRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
721e89bb428SRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
722e89bb428SRuslan Bilovol 	struct g_audio *audio_dev = uac->audio_dev;
723e89bb428SRuslan Bilovol 	struct uac_params *params = &audio_dev->params;
724e89bb428SRuslan Bilovol 	unsigned int pitch_min, pitch_max;
725e89bb428SRuslan Bilovol 
726e89bb428SRuslan Bilovol 	pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
727e89bb428SRuslan Bilovol 	pitch_max = (1000 + params->fb_max) * 1000;
728e89bb428SRuslan Bilovol 
729e89bb428SRuslan Bilovol 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
730e89bb428SRuslan Bilovol 	uinfo->count = 1;
731e89bb428SRuslan Bilovol 	uinfo->value.integer.min = pitch_min;
732e89bb428SRuslan Bilovol 	uinfo->value.integer.max = pitch_max;
733e89bb428SRuslan Bilovol 	uinfo->value.integer.step = 1;
734e89bb428SRuslan Bilovol 	return 0;
735e89bb428SRuslan Bilovol }
736e89bb428SRuslan Bilovol 
737e89bb428SRuslan Bilovol static int u_audio_pitch_get(struct snd_kcontrol *kcontrol,
738e89bb428SRuslan Bilovol 				   struct snd_ctl_elem_value *ucontrol)
739e89bb428SRuslan Bilovol {
740e89bb428SRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
741e89bb428SRuslan Bilovol 
742e89bb428SRuslan Bilovol 	ucontrol->value.integer.value[0] = prm->pitch;
743e89bb428SRuslan Bilovol 
744e89bb428SRuslan Bilovol 	return 0;
745e89bb428SRuslan Bilovol }
746e89bb428SRuslan Bilovol 
747e89bb428SRuslan Bilovol static int u_audio_pitch_put(struct snd_kcontrol *kcontrol,
748e89bb428SRuslan Bilovol 				  struct snd_ctl_elem_value *ucontrol)
749e89bb428SRuslan Bilovol {
750e89bb428SRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
751e89bb428SRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
752e89bb428SRuslan Bilovol 	struct g_audio *audio_dev = uac->audio_dev;
753e89bb428SRuslan Bilovol 	struct uac_params *params = &audio_dev->params;
754e89bb428SRuslan Bilovol 	unsigned int val;
755e89bb428SRuslan Bilovol 	unsigned int pitch_min, pitch_max;
756e89bb428SRuslan Bilovol 	int change = 0;
757e89bb428SRuslan Bilovol 
758e89bb428SRuslan Bilovol 	pitch_min = (1000 - FBACK_SLOW_MAX) * 1000;
759e89bb428SRuslan Bilovol 	pitch_max = (1000 + params->fb_max) * 1000;
760e89bb428SRuslan Bilovol 
761e89bb428SRuslan Bilovol 	val = ucontrol->value.integer.value[0];
762e89bb428SRuslan Bilovol 
763e89bb428SRuslan Bilovol 	if (val < pitch_min)
764e89bb428SRuslan Bilovol 		val = pitch_min;
765e89bb428SRuslan Bilovol 	if (val > pitch_max)
766e89bb428SRuslan Bilovol 		val = pitch_max;
767e89bb428SRuslan Bilovol 
768e89bb428SRuslan Bilovol 	if (prm->pitch != val) {
769e89bb428SRuslan Bilovol 		prm->pitch = val;
770e89bb428SRuslan Bilovol 		change = 1;
771e89bb428SRuslan Bilovol 	}
772e89bb428SRuslan Bilovol 
773e89bb428SRuslan Bilovol 	return change;
774e89bb428SRuslan Bilovol }
775e89bb428SRuslan Bilovol 
776*02de698cSRuslan Bilovol static int u_audio_mute_info(struct snd_kcontrol *kcontrol,
777*02de698cSRuslan Bilovol 				   struct snd_ctl_elem_info *uinfo)
778e89bb428SRuslan Bilovol {
779*02de698cSRuslan Bilovol 	uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
780*02de698cSRuslan Bilovol 	uinfo->count = 1;
781*02de698cSRuslan Bilovol 	uinfo->value.integer.min = 0;
782*02de698cSRuslan Bilovol 	uinfo->value.integer.max = 1;
783*02de698cSRuslan Bilovol 	uinfo->value.integer.step = 1;
784*02de698cSRuslan Bilovol 
785*02de698cSRuslan Bilovol 	return 0;
786*02de698cSRuslan Bilovol }
787*02de698cSRuslan Bilovol 
788*02de698cSRuslan Bilovol static int u_audio_mute_get(struct snd_kcontrol *kcontrol,
789*02de698cSRuslan Bilovol 				   struct snd_ctl_elem_value *ucontrol)
790*02de698cSRuslan Bilovol {
791*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
792*02de698cSRuslan Bilovol 	unsigned long flags;
793*02de698cSRuslan Bilovol 
794*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
795*02de698cSRuslan Bilovol 	ucontrol->value.integer.value[0] = !prm->mute;
796*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
797*02de698cSRuslan Bilovol 
798*02de698cSRuslan Bilovol 	return 0;
799*02de698cSRuslan Bilovol }
800*02de698cSRuslan Bilovol 
801*02de698cSRuslan Bilovol static int u_audio_mute_put(struct snd_kcontrol *kcontrol,
802*02de698cSRuslan Bilovol 				  struct snd_ctl_elem_value *ucontrol)
803*02de698cSRuslan Bilovol {
804*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
805*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
806*02de698cSRuslan Bilovol 	struct g_audio *audio_dev = uac->audio_dev;
807*02de698cSRuslan Bilovol 	unsigned int val;
808*02de698cSRuslan Bilovol 	unsigned long flags;
809*02de698cSRuslan Bilovol 	int change = 0;
810*02de698cSRuslan Bilovol 
811*02de698cSRuslan Bilovol 	val = !ucontrol->value.integer.value[0];
812*02de698cSRuslan Bilovol 
813*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
814*02de698cSRuslan Bilovol 	if (val != prm->mute) {
815*02de698cSRuslan Bilovol 		prm->mute = val;
816*02de698cSRuslan Bilovol 		change = 1;
817*02de698cSRuslan Bilovol 	}
818*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
819*02de698cSRuslan Bilovol 
820*02de698cSRuslan Bilovol 	if (change && audio_dev->notify)
821*02de698cSRuslan Bilovol 		audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_MUTE);
822*02de698cSRuslan Bilovol 
823*02de698cSRuslan Bilovol 	return change;
824*02de698cSRuslan Bilovol }
825*02de698cSRuslan Bilovol 
826*02de698cSRuslan Bilovol /*
827*02de698cSRuslan Bilovol  * TLV callback for mixer volume controls
828*02de698cSRuslan Bilovol  */
829*02de698cSRuslan Bilovol static int u_audio_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
830*02de698cSRuslan Bilovol 			 unsigned int size, unsigned int __user *_tlv)
831*02de698cSRuslan Bilovol {
832*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
833*02de698cSRuslan Bilovol 	DECLARE_TLV_DB_MINMAX(scale, 0, 0);
834*02de698cSRuslan Bilovol 
835*02de698cSRuslan Bilovol 	if (size < sizeof(scale))
836*02de698cSRuslan Bilovol 		return -ENOMEM;
837*02de698cSRuslan Bilovol 
838*02de698cSRuslan Bilovol 	/* UAC volume resolution is 1/256 dB, TLV is 1/100 dB */
839*02de698cSRuslan Bilovol 	scale[2] = (prm->volume_min * 100) / 256;
840*02de698cSRuslan Bilovol 	scale[3] = (prm->volume_max * 100) / 256;
841*02de698cSRuslan Bilovol 	if (copy_to_user(_tlv, scale, sizeof(scale)))
842*02de698cSRuslan Bilovol 		return -EFAULT;
843*02de698cSRuslan Bilovol 
844*02de698cSRuslan Bilovol 	return 0;
845*02de698cSRuslan Bilovol }
846*02de698cSRuslan Bilovol 
847*02de698cSRuslan Bilovol static int u_audio_volume_info(struct snd_kcontrol *kcontrol,
848*02de698cSRuslan Bilovol 				   struct snd_ctl_elem_info *uinfo)
849*02de698cSRuslan Bilovol {
850*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
851*02de698cSRuslan Bilovol 
852*02de698cSRuslan Bilovol 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
853*02de698cSRuslan Bilovol 	uinfo->count = 1;
854*02de698cSRuslan Bilovol 	uinfo->value.integer.min = 0;
855*02de698cSRuslan Bilovol 	uinfo->value.integer.max =
856*02de698cSRuslan Bilovol 		(prm->volume_max - prm->volume_min + prm->volume_res - 1)
857*02de698cSRuslan Bilovol 		/ prm->volume_res;
858*02de698cSRuslan Bilovol 	uinfo->value.integer.step = 1;
859*02de698cSRuslan Bilovol 
860*02de698cSRuslan Bilovol 	return 0;
861*02de698cSRuslan Bilovol }
862*02de698cSRuslan Bilovol 
863*02de698cSRuslan Bilovol static int u_audio_volume_get(struct snd_kcontrol *kcontrol,
864*02de698cSRuslan Bilovol 				   struct snd_ctl_elem_value *ucontrol)
865*02de698cSRuslan Bilovol {
866*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
867*02de698cSRuslan Bilovol 	unsigned long flags;
868*02de698cSRuslan Bilovol 
869*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
870*02de698cSRuslan Bilovol 	ucontrol->value.integer.value[0] =
871*02de698cSRuslan Bilovol 			(prm->volume - prm->volume_min) / prm->volume_res;
872*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
873*02de698cSRuslan Bilovol 
874*02de698cSRuslan Bilovol 	return 0;
875*02de698cSRuslan Bilovol }
876*02de698cSRuslan Bilovol 
877*02de698cSRuslan Bilovol static int u_audio_volume_put(struct snd_kcontrol *kcontrol,
878*02de698cSRuslan Bilovol 				  struct snd_ctl_elem_value *ucontrol)
879*02de698cSRuslan Bilovol {
880*02de698cSRuslan Bilovol 	struct uac_rtd_params *prm = snd_kcontrol_chip(kcontrol);
881*02de698cSRuslan Bilovol 	struct snd_uac_chip *uac = prm->uac;
882*02de698cSRuslan Bilovol 	struct g_audio *audio_dev = uac->audio_dev;
883*02de698cSRuslan Bilovol 	unsigned int val;
884*02de698cSRuslan Bilovol 	s16 volume;
885*02de698cSRuslan Bilovol 	unsigned long flags;
886*02de698cSRuslan Bilovol 	int change = 0;
887*02de698cSRuslan Bilovol 
888*02de698cSRuslan Bilovol 	val = ucontrol->value.integer.value[0];
889*02de698cSRuslan Bilovol 
890*02de698cSRuslan Bilovol 	spin_lock_irqsave(&prm->lock, flags);
891*02de698cSRuslan Bilovol 	volume = (val * prm->volume_res) + prm->volume_min;
892*02de698cSRuslan Bilovol 	volume = clamp(volume, prm->volume_min, prm->volume_max);
893*02de698cSRuslan Bilovol 	if (volume != prm->volume) {
894*02de698cSRuslan Bilovol 		prm->volume = volume;
895*02de698cSRuslan Bilovol 		change = 1;
896*02de698cSRuslan Bilovol 	}
897*02de698cSRuslan Bilovol 	spin_unlock_irqrestore(&prm->lock, flags);
898*02de698cSRuslan Bilovol 
899*02de698cSRuslan Bilovol 	if (change && audio_dev->notify)
900*02de698cSRuslan Bilovol 		audio_dev->notify(audio_dev, prm->fu_id, UAC_FU_VOLUME);
901*02de698cSRuslan Bilovol 
902*02de698cSRuslan Bilovol 	return change;
903*02de698cSRuslan Bilovol }
904*02de698cSRuslan Bilovol 
905*02de698cSRuslan Bilovol 
906*02de698cSRuslan Bilovol static struct snd_kcontrol_new u_audio_controls[]  = {
907*02de698cSRuslan Bilovol   [UAC_FBACK_CTRL] {
908e89bb428SRuslan Bilovol     .iface =        SNDRV_CTL_ELEM_IFACE_PCM,
909e89bb428SRuslan Bilovol     .name =         "Capture Pitch 1000000",
910e89bb428SRuslan Bilovol     .info =         u_audio_pitch_info,
911e89bb428SRuslan Bilovol     .get =          u_audio_pitch_get,
912e89bb428SRuslan Bilovol     .put =          u_audio_pitch_put,
913e89bb428SRuslan Bilovol   },
914*02de698cSRuslan Bilovol   [UAC_MUTE_CTRL] {
915*02de698cSRuslan Bilovol 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
916*02de698cSRuslan Bilovol 		.name =		"", /* will be filled later */
917*02de698cSRuslan Bilovol 		.info =		u_audio_mute_info,
918*02de698cSRuslan Bilovol 		.get =		u_audio_mute_get,
919*02de698cSRuslan Bilovol 		.put =		u_audio_mute_put,
920*02de698cSRuslan Bilovol 	},
921*02de698cSRuslan Bilovol 	[UAC_VOLUME_CTRL] {
922*02de698cSRuslan Bilovol 		.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
923*02de698cSRuslan Bilovol 		.name =		"", /* will be filled later */
924*02de698cSRuslan Bilovol 		.info =		u_audio_volume_info,
925*02de698cSRuslan Bilovol 		.get =		u_audio_volume_get,
926*02de698cSRuslan Bilovol 		.put =		u_audio_volume_put,
927*02de698cSRuslan Bilovol 	},
928e89bb428SRuslan Bilovol };
929e89bb428SRuslan Bilovol 
930eb9fecb9SRuslan Bilovol int g_audio_setup(struct g_audio *g_audio, const char *pcm_name,
931eb9fecb9SRuslan Bilovol 					const char *card_name)
932eb9fecb9SRuslan Bilovol {
933eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac;
934eb9fecb9SRuslan Bilovol 	struct snd_card *card;
935eb9fecb9SRuslan Bilovol 	struct snd_pcm *pcm;
936e89bb428SRuslan Bilovol 	struct snd_kcontrol *kctl;
937eb9fecb9SRuslan Bilovol 	struct uac_params *params;
938eb9fecb9SRuslan Bilovol 	int p_chmask, c_chmask;
939*02de698cSRuslan Bilovol 	int i, err;
940eb9fecb9SRuslan Bilovol 
941eb9fecb9SRuslan Bilovol 	if (!g_audio)
942eb9fecb9SRuslan Bilovol 		return -EINVAL;
943eb9fecb9SRuslan Bilovol 
944eb9fecb9SRuslan Bilovol 	uac = kzalloc(sizeof(*uac), GFP_KERNEL);
945eb9fecb9SRuslan Bilovol 	if (!uac)
946eb9fecb9SRuslan Bilovol 		return -ENOMEM;
947eb9fecb9SRuslan Bilovol 	g_audio->uac = uac;
948eb9fecb9SRuslan Bilovol 	uac->audio_dev = g_audio;
949eb9fecb9SRuslan Bilovol 
950eb9fecb9SRuslan Bilovol 	params = &g_audio->params;
951eb9fecb9SRuslan Bilovol 	p_chmask = params->p_chmask;
952eb9fecb9SRuslan Bilovol 	c_chmask = params->c_chmask;
953eb9fecb9SRuslan Bilovol 
954eb9fecb9SRuslan Bilovol 	if (c_chmask) {
955eb9fecb9SRuslan Bilovol 		struct uac_rtd_params *prm = &uac->c_prm;
956eb9fecb9SRuslan Bilovol 
957*02de698cSRuslan Bilovol     spin_lock_init(&prm->lock);
958eb9fecb9SRuslan Bilovol     uac->c_prm.uac = uac;
959eb9fecb9SRuslan Bilovol 		prm->max_psize = g_audio->out_ep_maxpsize;
960eb9fecb9SRuslan Bilovol 
96129865117SJerome Brunet 		prm->reqs = kcalloc(params->req_number,
96229865117SJerome Brunet 				    sizeof(struct usb_request *),
963eb9fecb9SRuslan Bilovol 				    GFP_KERNEL);
96429865117SJerome Brunet 		if (!prm->reqs) {
965eb9fecb9SRuslan Bilovol 			err = -ENOMEM;
966eb9fecb9SRuslan Bilovol 			goto fail;
967eb9fecb9SRuslan Bilovol 		}
968eb9fecb9SRuslan Bilovol 
969eb9fecb9SRuslan Bilovol 		prm->rbuf = kcalloc(params->req_number, prm->max_psize,
970eb9fecb9SRuslan Bilovol 				GFP_KERNEL);
971eb9fecb9SRuslan Bilovol 		if (!prm->rbuf) {
972eb9fecb9SRuslan Bilovol 			prm->max_psize = 0;
973eb9fecb9SRuslan Bilovol 			err = -ENOMEM;
974eb9fecb9SRuslan Bilovol 			goto fail;
975eb9fecb9SRuslan Bilovol 		}
976eb9fecb9SRuslan Bilovol 	}
977eb9fecb9SRuslan Bilovol 
978eb9fecb9SRuslan Bilovol 	if (p_chmask) {
979eb9fecb9SRuslan Bilovol 		struct uac_rtd_params *prm = &uac->p_prm;
980eb9fecb9SRuslan Bilovol 
981*02de698cSRuslan Bilovol 		spin_lock_init(&prm->lock);
982eb9fecb9SRuslan Bilovol 		uac->p_prm.uac = uac;
983eb9fecb9SRuslan Bilovol 		prm->max_psize = g_audio->in_ep_maxpsize;
984eb9fecb9SRuslan Bilovol 
98529865117SJerome Brunet 		prm->reqs = kcalloc(params->req_number,
98629865117SJerome Brunet 				    sizeof(struct usb_request *),
987eb9fecb9SRuslan Bilovol 				    GFP_KERNEL);
98829865117SJerome Brunet 		if (!prm->reqs) {
989eb9fecb9SRuslan Bilovol 			err = -ENOMEM;
990eb9fecb9SRuslan Bilovol 			goto fail;
991eb9fecb9SRuslan Bilovol 		}
992eb9fecb9SRuslan Bilovol 
993eb9fecb9SRuslan Bilovol 		prm->rbuf = kcalloc(params->req_number, prm->max_psize,
994eb9fecb9SRuslan Bilovol 				GFP_KERNEL);
995eb9fecb9SRuslan Bilovol 		if (!prm->rbuf) {
996eb9fecb9SRuslan Bilovol 			prm->max_psize = 0;
997eb9fecb9SRuslan Bilovol 			err = -ENOMEM;
998eb9fecb9SRuslan Bilovol 			goto fail;
999eb9fecb9SRuslan Bilovol 		}
1000eb9fecb9SRuslan Bilovol 	}
1001eb9fecb9SRuslan Bilovol 
1002eb9fecb9SRuslan Bilovol 	/* Choose any slot, with no id */
1003eb9fecb9SRuslan Bilovol 	err = snd_card_new(&g_audio->gadget->dev,
1004eb9fecb9SRuslan Bilovol 			-1, NULL, THIS_MODULE, 0, &card);
1005eb9fecb9SRuslan Bilovol 	if (err < 0)
1006eb9fecb9SRuslan Bilovol 		goto fail;
1007eb9fecb9SRuslan Bilovol 
1008eb9fecb9SRuslan Bilovol 	uac->card = card;
1009eb9fecb9SRuslan Bilovol 
1010eb9fecb9SRuslan Bilovol 	/*
1011eb9fecb9SRuslan Bilovol 	 * Create first PCM device
1012eb9fecb9SRuslan Bilovol 	 * Create a substream only for non-zero channel streams
1013eb9fecb9SRuslan Bilovol 	 */
1014eb9fecb9SRuslan Bilovol 	err = snd_pcm_new(uac->card, pcm_name, 0,
1015eb9fecb9SRuslan Bilovol 			       p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm);
1016eb9fecb9SRuslan Bilovol 	if (err < 0)
1017eb9fecb9SRuslan Bilovol 		goto snd_fail;
1018eb9fecb9SRuslan Bilovol 
1019d23922fcSRuslan Bilovol 	strscpy(pcm->name, pcm_name, sizeof(pcm->name));
1020eb9fecb9SRuslan Bilovol 	pcm->private_data = uac;
1021eb9fecb9SRuslan Bilovol 	uac->pcm = pcm;
1022eb9fecb9SRuslan Bilovol 
1023eb9fecb9SRuslan Bilovol 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac_pcm_ops);
1024eb9fecb9SRuslan Bilovol 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac_pcm_ops);
1025eb9fecb9SRuslan Bilovol 
1026*02de698cSRuslan Bilovol 	/*
1027*02de698cSRuslan Bilovol 	 * Create mixer and controls
1028*02de698cSRuslan Bilovol 	 * Create only if it's required on USB side
1029*02de698cSRuslan Bilovol 	 */
1030*02de698cSRuslan Bilovol 	if ((c_chmask && g_audio->in_ep_fback)
1031*02de698cSRuslan Bilovol 			|| (p_chmask && params->p_fu.id)
1032*02de698cSRuslan Bilovol 			|| (c_chmask && params->c_fu.id))
1033e89bb428SRuslan Bilovol 		strscpy(card->mixername, card_name, sizeof(card->driver));
1034e89bb428SRuslan Bilovol 
1035*02de698cSRuslan Bilovol 	if (c_chmask && g_audio->in_ep_fback) {
1036*02de698cSRuslan Bilovol 		kctl = snd_ctl_new1(&u_audio_controls[UAC_FBACK_CTRL],
1037*02de698cSRuslan Bilovol 				    &uac->c_prm);
1038e89bb428SRuslan Bilovol 		if (!kctl) {
1039e89bb428SRuslan Bilovol 			err = -ENOMEM;
1040e89bb428SRuslan Bilovol 			goto snd_fail;
1041e89bb428SRuslan Bilovol 		}
1042e89bb428SRuslan Bilovol 
1043e89bb428SRuslan Bilovol 		kctl->id.device = pcm->device;
1044e89bb428SRuslan Bilovol 		kctl->id.subdevice = 0;
1045e89bb428SRuslan Bilovol 
1046e89bb428SRuslan Bilovol 		err = snd_ctl_add(card, kctl);
1047e89bb428SRuslan Bilovol 		if (err < 0)
1048e89bb428SRuslan Bilovol 			goto snd_fail;
1049e89bb428SRuslan Bilovol 	}
1050e89bb428SRuslan Bilovol 
1051*02de698cSRuslan Bilovol 	for (i = 0; i <= SNDRV_PCM_STREAM_LAST; i++) {
1052*02de698cSRuslan Bilovol 		struct uac_rtd_params *prm;
1053*02de698cSRuslan Bilovol 		struct uac_fu_params *fu;
1054*02de698cSRuslan Bilovol 		char ctrl_name[24];
1055*02de698cSRuslan Bilovol 		char *direction;
1056*02de698cSRuslan Bilovol 
1057*02de698cSRuslan Bilovol 		if (!pcm->streams[i].substream_count)
1058*02de698cSRuslan Bilovol 			continue;
1059*02de698cSRuslan Bilovol 
1060*02de698cSRuslan Bilovol 		if (i == SNDRV_PCM_STREAM_PLAYBACK) {
1061*02de698cSRuslan Bilovol 			prm = &uac->p_prm;
1062*02de698cSRuslan Bilovol 			fu = &params->p_fu;
1063*02de698cSRuslan Bilovol 			direction = "Playback";
1064*02de698cSRuslan Bilovol 		} else {
1065*02de698cSRuslan Bilovol 			prm = &uac->c_prm;
1066*02de698cSRuslan Bilovol 			fu = &params->c_fu;
1067*02de698cSRuslan Bilovol 			direction = "Capture";
1068*02de698cSRuslan Bilovol 		}
1069*02de698cSRuslan Bilovol 
1070*02de698cSRuslan Bilovol 		prm->fu_id = fu->id;
1071*02de698cSRuslan Bilovol 
1072*02de698cSRuslan Bilovol 		if (fu->mute_present) {
1073*02de698cSRuslan Bilovol 			snprintf(ctrl_name, sizeof(ctrl_name),
1074*02de698cSRuslan Bilovol 					"PCM %s Switch", direction);
1075*02de698cSRuslan Bilovol 
1076*02de698cSRuslan Bilovol 			u_audio_controls[UAC_MUTE_CTRL].name = ctrl_name;
1077*02de698cSRuslan Bilovol 
1078*02de698cSRuslan Bilovol 			kctl = snd_ctl_new1(&u_audio_controls[UAC_MUTE_CTRL],
1079*02de698cSRuslan Bilovol 					    prm);
1080*02de698cSRuslan Bilovol 			if (!kctl) {
1081*02de698cSRuslan Bilovol 				err = -ENOMEM;
1082*02de698cSRuslan Bilovol 				goto snd_fail;
1083*02de698cSRuslan Bilovol 			}
1084*02de698cSRuslan Bilovol 
1085*02de698cSRuslan Bilovol 			kctl->id.device = pcm->device;
1086*02de698cSRuslan Bilovol 			kctl->id.subdevice = i;
1087*02de698cSRuslan Bilovol 
1088*02de698cSRuslan Bilovol 			err = snd_ctl_add(card, kctl);
1089*02de698cSRuslan Bilovol 			if (err < 0)
1090*02de698cSRuslan Bilovol 				goto snd_fail;
1091*02de698cSRuslan Bilovol 			prm->snd_kctl_mute = kctl;
1092*02de698cSRuslan Bilovol 			prm->mute = 0;
1093*02de698cSRuslan Bilovol 		}
1094*02de698cSRuslan Bilovol 
1095*02de698cSRuslan Bilovol 		if (fu->volume_present) {
1096*02de698cSRuslan Bilovol 			snprintf(ctrl_name, sizeof(ctrl_name),
1097*02de698cSRuslan Bilovol 					"PCM %s Volume", direction);
1098*02de698cSRuslan Bilovol 
1099*02de698cSRuslan Bilovol 			u_audio_controls[UAC_VOLUME_CTRL].name = ctrl_name;
1100*02de698cSRuslan Bilovol 
1101*02de698cSRuslan Bilovol 			kctl = snd_ctl_new1(&u_audio_controls[UAC_VOLUME_CTRL],
1102*02de698cSRuslan Bilovol 					    prm);
1103*02de698cSRuslan Bilovol 			if (!kctl) {
1104*02de698cSRuslan Bilovol 				err = -ENOMEM;
1105*02de698cSRuslan Bilovol 				goto snd_fail;
1106*02de698cSRuslan Bilovol 			}
1107*02de698cSRuslan Bilovol 
1108*02de698cSRuslan Bilovol 			kctl->id.device = pcm->device;
1109*02de698cSRuslan Bilovol 			kctl->id.subdevice = i;
1110*02de698cSRuslan Bilovol 
1111*02de698cSRuslan Bilovol 
1112*02de698cSRuslan Bilovol 			kctl->tlv.c = u_audio_volume_tlv;
1113*02de698cSRuslan Bilovol 			kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ |
1114*02de698cSRuslan Bilovol 					SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1115*02de698cSRuslan Bilovol 
1116*02de698cSRuslan Bilovol 			err = snd_ctl_add(card, kctl);
1117*02de698cSRuslan Bilovol 			if (err < 0)
1118*02de698cSRuslan Bilovol 				goto snd_fail;
1119*02de698cSRuslan Bilovol 			prm->snd_kctl_volume = kctl;
1120*02de698cSRuslan Bilovol 			prm->volume = fu->volume_max;
1121*02de698cSRuslan Bilovol 			prm->volume_max = fu->volume_max;
1122*02de698cSRuslan Bilovol 			prm->volume_min = fu->volume_min;
1123*02de698cSRuslan Bilovol 			prm->volume_res = fu->volume_res;
1124*02de698cSRuslan Bilovol 		}
1125*02de698cSRuslan Bilovol 	}
1126*02de698cSRuslan Bilovol 
1127d23922fcSRuslan Bilovol 	strscpy(card->driver, card_name, sizeof(card->driver));
1128d23922fcSRuslan Bilovol 	strscpy(card->shortname, card_name, sizeof(card->shortname));
1129eb9fecb9SRuslan Bilovol 	sprintf(card->longname, "%s %i", card_name, card->dev->id);
1130eb9fecb9SRuslan Bilovol 
1131d27ab1e6STakashi Iwai 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
113267b2945dSTakashi Iwai 				       NULL, 0, BUFF_SIZE_MAX);
1133eb9fecb9SRuslan Bilovol 
1134eb9fecb9SRuslan Bilovol 	err = snd_card_register(card);
1135eb9fecb9SRuslan Bilovol 
1136eb9fecb9SRuslan Bilovol 	if (!err)
1137eb9fecb9SRuslan Bilovol 		return 0;
1138eb9fecb9SRuslan Bilovol 
1139eb9fecb9SRuslan Bilovol snd_fail:
1140eb9fecb9SRuslan Bilovol 	snd_card_free(card);
1141eb9fecb9SRuslan Bilovol fail:
114229865117SJerome Brunet 	kfree(uac->p_prm.reqs);
114329865117SJerome Brunet 	kfree(uac->c_prm.reqs);
1144eb9fecb9SRuslan Bilovol 	kfree(uac->p_prm.rbuf);
1145eb9fecb9SRuslan Bilovol 	kfree(uac->c_prm.rbuf);
1146eb9fecb9SRuslan Bilovol 	kfree(uac);
1147eb9fecb9SRuslan Bilovol 
1148eb9fecb9SRuslan Bilovol 	return err;
1149eb9fecb9SRuslan Bilovol }
1150eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(g_audio_setup);
1151eb9fecb9SRuslan Bilovol 
1152eb9fecb9SRuslan Bilovol void g_audio_cleanup(struct g_audio *g_audio)
1153eb9fecb9SRuslan Bilovol {
1154eb9fecb9SRuslan Bilovol 	struct snd_uac_chip *uac;
1155eb9fecb9SRuslan Bilovol 	struct snd_card *card;
1156eb9fecb9SRuslan Bilovol 
1157eb9fecb9SRuslan Bilovol 	if (!g_audio || !g_audio->uac)
1158eb9fecb9SRuslan Bilovol 		return;
1159eb9fecb9SRuslan Bilovol 
1160eb9fecb9SRuslan Bilovol 	uac = g_audio->uac;
1161eb9fecb9SRuslan Bilovol 	card = uac->card;
1162eb9fecb9SRuslan Bilovol 	if (card)
1163eb9fecb9SRuslan Bilovol 		snd_card_free(card);
1164eb9fecb9SRuslan Bilovol 
116529865117SJerome Brunet 	kfree(uac->p_prm.reqs);
116629865117SJerome Brunet 	kfree(uac->c_prm.reqs);
1167eb9fecb9SRuslan Bilovol 	kfree(uac->p_prm.rbuf);
1168eb9fecb9SRuslan Bilovol 	kfree(uac->c_prm.rbuf);
1169eb9fecb9SRuslan Bilovol 	kfree(uac);
1170eb9fecb9SRuslan Bilovol }
1171eb9fecb9SRuslan Bilovol EXPORT_SYMBOL_GPL(g_audio_cleanup);
1172eb9fecb9SRuslan Bilovol 
1173eb9fecb9SRuslan Bilovol MODULE_LICENSE("GPL");
1174eb9fecb9SRuslan Bilovol MODULE_DESCRIPTION("USB gadget \"ALSA sound card\" utilities");
1175eb9fecb9SRuslan Bilovol MODULE_AUTHOR("Ruslan Bilovol");
1176