xref: /OK3568_Linux_fs/kernel/sound/usb/usx2y/usbusx2yaudio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *   US-X2Y AUDIO
4*4882a593Smuzhiyun  *   Copyright (c) 2002-2004 by Karsten Wiese
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *   based on
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *   (Tentative) USB Audio Driver for ALSA
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *   Main and PCM part
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  *   Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de>
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *   Many codes borrowed from audio.c by
15*4882a593Smuzhiyun  *	    Alan Cox (alan@lxorguk.ukuu.org.uk)
16*4882a593Smuzhiyun  *	    Thomas Sailer (sailer@ife.ee.ethz.ch)
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/interrupt.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/usb.h>
23*4882a593Smuzhiyun #include <linux/moduleparam.h>
24*4882a593Smuzhiyun #include <sound/core.h>
25*4882a593Smuzhiyun #include <sound/info.h>
26*4882a593Smuzhiyun #include <sound/pcm.h>
27*4882a593Smuzhiyun #include <sound/pcm_params.h>
28*4882a593Smuzhiyun #include "usx2y.h"
29*4882a593Smuzhiyun #include "usbusx2y.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define USX2Y_NRPACKS 4			/* Default value used for nr of packs per urb.
32*4882a593Smuzhiyun 					  1 to 4 have been tested ok on uhci.
33*4882a593Smuzhiyun 					  To use 3 on ohci, you'd need a patch:
34*4882a593Smuzhiyun 					  look for "0000425-linux-2.6.9-rc4-mm1_ohci-hcd.patch.gz" on
35*4882a593Smuzhiyun 					  "https://bugtrack.alsa-project.org/alsa-bug/bug_view_page.php?bug_id=0000425"
36*4882a593Smuzhiyun 					  .
37*4882a593Smuzhiyun 					  1, 2 and 4 work out of the box on ohci, if I recall correctly.
38*4882a593Smuzhiyun 					  Bigger is safer operation,
39*4882a593Smuzhiyun 					  smaller gives lower latencies.
40*4882a593Smuzhiyun 					*/
41*4882a593Smuzhiyun #define USX2Y_NRPACKS_VARIABLE y	/* If your system works ok with this module's parameter
42*4882a593Smuzhiyun 					   nrpacks set to 1, you might as well comment
43*4882a593Smuzhiyun 					   this #define out, and thereby produce smaller, faster code.
44*4882a593Smuzhiyun 					   You'd also set USX2Y_NRPACKS to 1 then.
45*4882a593Smuzhiyun 					*/
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #ifdef USX2Y_NRPACKS_VARIABLE
48*4882a593Smuzhiyun  static int nrpacks = USX2Y_NRPACKS; /* number of packets per urb */
49*4882a593Smuzhiyun  #define  nr_of_packs() nrpacks
50*4882a593Smuzhiyun  module_param(nrpacks, int, 0444);
51*4882a593Smuzhiyun  MODULE_PARM_DESC(nrpacks, "Number of packets per URB.");
52*4882a593Smuzhiyun #else
53*4882a593Smuzhiyun  #define nr_of_packs() USX2Y_NRPACKS
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 
usx2y_urb_capt_retire(struct snd_usx2y_substream * subs)57*4882a593Smuzhiyun static int usx2y_urb_capt_retire(struct snd_usx2y_substream *subs)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct urb	*urb = subs->completed_urb;
60*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
61*4882a593Smuzhiyun 	unsigned char	*cp;
62*4882a593Smuzhiyun 	int 		i, len, lens = 0, hwptr_done = subs->hwptr_done;
63*4882a593Smuzhiyun 	struct usx2ydev	*usx2y = subs->usx2y;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	for (i = 0; i < nr_of_packs(); i++) {
66*4882a593Smuzhiyun 		cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
67*4882a593Smuzhiyun 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
68*4882a593Smuzhiyun 			snd_printk(KERN_ERR "active frame status %i. "
69*4882a593Smuzhiyun 				   "Most probably some hardware problem.\n",
70*4882a593Smuzhiyun 				   urb->iso_frame_desc[i].status);
71*4882a593Smuzhiyun 			return urb->iso_frame_desc[i].status;
72*4882a593Smuzhiyun 		}
73*4882a593Smuzhiyun 		len = urb->iso_frame_desc[i].actual_length / usx2y->stride;
74*4882a593Smuzhiyun 		if (! len) {
75*4882a593Smuzhiyun 			snd_printd("0 == len ERROR!\n");
76*4882a593Smuzhiyun 			continue;
77*4882a593Smuzhiyun 		}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		/* copy a data chunk */
80*4882a593Smuzhiyun 		if ((hwptr_done + len) > runtime->buffer_size) {
81*4882a593Smuzhiyun 			int cnt = runtime->buffer_size - hwptr_done;
82*4882a593Smuzhiyun 			int blen = cnt * usx2y->stride;
83*4882a593Smuzhiyun 			memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp, blen);
84*4882a593Smuzhiyun 			memcpy(runtime->dma_area, cp + blen, len * usx2y->stride - blen);
85*4882a593Smuzhiyun 		} else {
86*4882a593Smuzhiyun 			memcpy(runtime->dma_area + hwptr_done * usx2y->stride, cp,
87*4882a593Smuzhiyun 			       len * usx2y->stride);
88*4882a593Smuzhiyun 		}
89*4882a593Smuzhiyun 		lens += len;
90*4882a593Smuzhiyun 		if ((hwptr_done += len) >= runtime->buffer_size)
91*4882a593Smuzhiyun 			hwptr_done -= runtime->buffer_size;
92*4882a593Smuzhiyun 	}
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	subs->hwptr_done = hwptr_done;
95*4882a593Smuzhiyun 	subs->transfer_done += lens;
96*4882a593Smuzhiyun 	/* update the pointer, call callback if necessary */
97*4882a593Smuzhiyun 	if (subs->transfer_done >= runtime->period_size) {
98*4882a593Smuzhiyun 		subs->transfer_done -= runtime->period_size;
99*4882a593Smuzhiyun 		snd_pcm_period_elapsed(subs->pcm_substream);
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 	return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * prepare urb for playback data pipe
105*4882a593Smuzhiyun  *
106*4882a593Smuzhiyun  * we copy the data directly from the pcm buffer.
107*4882a593Smuzhiyun  * the current position to be copied is held in hwptr field.
108*4882a593Smuzhiyun  * since a urb can handle only a single linear buffer, if the total
109*4882a593Smuzhiyun  * transferred area overflows the buffer boundary, we cannot send
110*4882a593Smuzhiyun  * it directly from the buffer.  thus the data is once copied to
111*4882a593Smuzhiyun  * a temporary buffer and urb points to that.
112*4882a593Smuzhiyun  */
usx2y_urb_play_prepare(struct snd_usx2y_substream * subs,struct urb * cap_urb,struct urb * urb)113*4882a593Smuzhiyun static int usx2y_urb_play_prepare(struct snd_usx2y_substream *subs,
114*4882a593Smuzhiyun 				  struct urb *cap_urb,
115*4882a593Smuzhiyun 				  struct urb *urb)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	int count, counts, pack;
118*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
119*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	count = 0;
122*4882a593Smuzhiyun 	for (pack = 0; pack <  nr_of_packs(); pack++) {
123*4882a593Smuzhiyun 		/* calculate the size of a packet */
124*4882a593Smuzhiyun 		counts = cap_urb->iso_frame_desc[pack].actual_length / usx2y->stride;
125*4882a593Smuzhiyun 		count += counts;
126*4882a593Smuzhiyun 		if (counts < 43 || counts > 50) {
127*4882a593Smuzhiyun 			snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
128*4882a593Smuzhiyun 			return -EPIPE;
129*4882a593Smuzhiyun 		}
130*4882a593Smuzhiyun 		/* set up descriptor */
131*4882a593Smuzhiyun 		urb->iso_frame_desc[pack].offset = pack ?
132*4882a593Smuzhiyun 			urb->iso_frame_desc[pack - 1].offset +
133*4882a593Smuzhiyun 			urb->iso_frame_desc[pack - 1].length :
134*4882a593Smuzhiyun 			0;
135*4882a593Smuzhiyun 		urb->iso_frame_desc[pack].length = cap_urb->iso_frame_desc[pack].actual_length;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 	if (atomic_read(&subs->state) >= STATE_PRERUNNING)
138*4882a593Smuzhiyun 		if (subs->hwptr + count > runtime->buffer_size) {
139*4882a593Smuzhiyun 			/* err, the transferred area goes over buffer boundary.
140*4882a593Smuzhiyun 			 * copy the data to the temp buffer.
141*4882a593Smuzhiyun 			 */
142*4882a593Smuzhiyun 			int len;
143*4882a593Smuzhiyun 			len = runtime->buffer_size - subs->hwptr;
144*4882a593Smuzhiyun 			urb->transfer_buffer = subs->tmpbuf;
145*4882a593Smuzhiyun 			memcpy(subs->tmpbuf, runtime->dma_area +
146*4882a593Smuzhiyun 			       subs->hwptr * usx2y->stride, len * usx2y->stride);
147*4882a593Smuzhiyun 			memcpy(subs->tmpbuf + len * usx2y->stride,
148*4882a593Smuzhiyun 			       runtime->dma_area, (count - len) * usx2y->stride);
149*4882a593Smuzhiyun 			subs->hwptr += count;
150*4882a593Smuzhiyun 			subs->hwptr -= runtime->buffer_size;
151*4882a593Smuzhiyun 		} else {
152*4882a593Smuzhiyun 			/* set the buffer pointer */
153*4882a593Smuzhiyun 			urb->transfer_buffer = runtime->dma_area + subs->hwptr * usx2y->stride;
154*4882a593Smuzhiyun 			if ((subs->hwptr += count) >= runtime->buffer_size)
155*4882a593Smuzhiyun 				subs->hwptr -= runtime->buffer_size;
156*4882a593Smuzhiyun 		}
157*4882a593Smuzhiyun 	else
158*4882a593Smuzhiyun 		urb->transfer_buffer = subs->tmpbuf;
159*4882a593Smuzhiyun 	urb->transfer_buffer_length = count * usx2y->stride;
160*4882a593Smuzhiyun 	return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun /*
164*4882a593Smuzhiyun  * process after playback data complete
165*4882a593Smuzhiyun  *
166*4882a593Smuzhiyun  * update the current position and call callback if a period is processed.
167*4882a593Smuzhiyun  */
usx2y_urb_play_retire(struct snd_usx2y_substream * subs,struct urb * urb)168*4882a593Smuzhiyun static void usx2y_urb_play_retire(struct snd_usx2y_substream *subs, struct urb *urb)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
171*4882a593Smuzhiyun 	int		len = urb->actual_length / subs->usx2y->stride;
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun 	subs->transfer_done += len;
174*4882a593Smuzhiyun 	subs->hwptr_done +=  len;
175*4882a593Smuzhiyun 	if (subs->hwptr_done >= runtime->buffer_size)
176*4882a593Smuzhiyun 		subs->hwptr_done -= runtime->buffer_size;
177*4882a593Smuzhiyun 	if (subs->transfer_done >= runtime->period_size) {
178*4882a593Smuzhiyun 		subs->transfer_done -= runtime->period_size;
179*4882a593Smuzhiyun 		snd_pcm_period_elapsed(subs->pcm_substream);
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
usx2y_urb_submit(struct snd_usx2y_substream * subs,struct urb * urb,int frame)183*4882a593Smuzhiyun static int usx2y_urb_submit(struct snd_usx2y_substream *subs, struct urb *urb, int frame)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	int err;
186*4882a593Smuzhiyun 	if (!urb)
187*4882a593Smuzhiyun 		return -ENODEV;
188*4882a593Smuzhiyun 	urb->start_frame = (frame + NRURBS * nr_of_packs());  // let hcd do rollover sanity checks
189*4882a593Smuzhiyun 	urb->hcpriv = NULL;
190*4882a593Smuzhiyun 	urb->dev = subs->usx2y->dev; /* we need to set this at each time */
191*4882a593Smuzhiyun 	if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
192*4882a593Smuzhiyun 		snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err);
193*4882a593Smuzhiyun 		return err;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
usx2y_usbframe_complete(struct snd_usx2y_substream * capsubs,struct snd_usx2y_substream * playbacksubs,int frame)198*4882a593Smuzhiyun static inline int usx2y_usbframe_complete(struct snd_usx2y_substream *capsubs,
199*4882a593Smuzhiyun 					  struct snd_usx2y_substream *playbacksubs,
200*4882a593Smuzhiyun 					  int frame)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	int err, state;
203*4882a593Smuzhiyun 	struct urb *urb = playbacksubs->completed_urb;
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	state = atomic_read(&playbacksubs->state);
206*4882a593Smuzhiyun 	if (NULL != urb) {
207*4882a593Smuzhiyun 		if (state == STATE_RUNNING)
208*4882a593Smuzhiyun 			usx2y_urb_play_retire(playbacksubs, urb);
209*4882a593Smuzhiyun 		else if (state >= STATE_PRERUNNING)
210*4882a593Smuzhiyun 			atomic_inc(&playbacksubs->state);
211*4882a593Smuzhiyun 	} else {
212*4882a593Smuzhiyun 		switch (state) {
213*4882a593Smuzhiyun 		case STATE_STARTING1:
214*4882a593Smuzhiyun 			urb = playbacksubs->urb[0];
215*4882a593Smuzhiyun 			atomic_inc(&playbacksubs->state);
216*4882a593Smuzhiyun 			break;
217*4882a593Smuzhiyun 		case STATE_STARTING2:
218*4882a593Smuzhiyun 			urb = playbacksubs->urb[1];
219*4882a593Smuzhiyun 			atomic_inc(&playbacksubs->state);
220*4882a593Smuzhiyun 			break;
221*4882a593Smuzhiyun 		}
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 	if (urb) {
224*4882a593Smuzhiyun 		if ((err = usx2y_urb_play_prepare(playbacksubs, capsubs->completed_urb, urb)) ||
225*4882a593Smuzhiyun 		    (err = usx2y_urb_submit(playbacksubs, urb, frame))) {
226*4882a593Smuzhiyun 			return err;
227*4882a593Smuzhiyun 		}
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	playbacksubs->completed_urb = NULL;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	state = atomic_read(&capsubs->state);
233*4882a593Smuzhiyun 	if (state >= STATE_PREPARED) {
234*4882a593Smuzhiyun 		if (state == STATE_RUNNING) {
235*4882a593Smuzhiyun 			if ((err = usx2y_urb_capt_retire(capsubs)))
236*4882a593Smuzhiyun 				return err;
237*4882a593Smuzhiyun 		} else if (state >= STATE_PRERUNNING)
238*4882a593Smuzhiyun 			atomic_inc(&capsubs->state);
239*4882a593Smuzhiyun 		if ((err = usx2y_urb_submit(capsubs, capsubs->completed_urb, frame)))
240*4882a593Smuzhiyun 			return err;
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 	capsubs->completed_urb = NULL;
243*4882a593Smuzhiyun 	return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 
usx2y_clients_stop(struct usx2ydev * usx2y)247*4882a593Smuzhiyun static void usx2y_clients_stop(struct usx2ydev *usx2y)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	int s, u;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	for (s = 0; s < 4; s++) {
252*4882a593Smuzhiyun 		struct snd_usx2y_substream *subs = usx2y->subs[s];
253*4882a593Smuzhiyun 		if (subs) {
254*4882a593Smuzhiyun 			snd_printdd("%i %p state=%i\n", s, subs, atomic_read(&subs->state));
255*4882a593Smuzhiyun 			atomic_set(&subs->state, STATE_STOPPED);
256*4882a593Smuzhiyun 		}
257*4882a593Smuzhiyun 	}
258*4882a593Smuzhiyun 	for (s = 0; s < 4; s++) {
259*4882a593Smuzhiyun 		struct snd_usx2y_substream *subs = usx2y->subs[s];
260*4882a593Smuzhiyun 		if (subs) {
261*4882a593Smuzhiyun 			if (atomic_read(&subs->state) >= STATE_PRERUNNING)
262*4882a593Smuzhiyun 				snd_pcm_stop_xrun(subs->pcm_substream);
263*4882a593Smuzhiyun 			for (u = 0; u < NRURBS; u++) {
264*4882a593Smuzhiyun 				struct urb *urb = subs->urb[u];
265*4882a593Smuzhiyun 				if (NULL != urb)
266*4882a593Smuzhiyun 					snd_printdd("%i status=%i start_frame=%i\n",
267*4882a593Smuzhiyun 						    u, urb->status, urb->start_frame);
268*4882a593Smuzhiyun 			}
269*4882a593Smuzhiyun 		}
270*4882a593Smuzhiyun 	}
271*4882a593Smuzhiyun 	usx2y->prepare_subs = NULL;
272*4882a593Smuzhiyun 	wake_up(&usx2y->prepare_wait_queue);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
usx2y_error_urb_status(struct usx2ydev * usx2y,struct snd_usx2y_substream * subs,struct urb * urb)275*4882a593Smuzhiyun static void usx2y_error_urb_status(struct usx2ydev *usx2y,
276*4882a593Smuzhiyun 				   struct snd_usx2y_substream *subs, struct urb *urb)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	snd_printk(KERN_ERR "ep=%i stalled with status=%i\n", subs->endpoint, urb->status);
279*4882a593Smuzhiyun 	urb->status = 0;
280*4882a593Smuzhiyun 	usx2y_clients_stop(usx2y);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
i_usx2y_urb_complete(struct urb * urb)283*4882a593Smuzhiyun static void i_usx2y_urb_complete(struct urb *urb)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = urb->context;
286*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	if (unlikely(atomic_read(&subs->state) < STATE_PREPARED)) {
289*4882a593Smuzhiyun 		snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
290*4882a593Smuzhiyun 			    usb_get_current_frame_number(usx2y->dev),
291*4882a593Smuzhiyun 			    subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
292*4882a593Smuzhiyun 			    urb->status, urb->start_frame);
293*4882a593Smuzhiyun 		return;
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 	if (unlikely(urb->status)) {
296*4882a593Smuzhiyun 		usx2y_error_urb_status(usx2y, subs, urb);
297*4882a593Smuzhiyun 		return;
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	subs->completed_urb = urb;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	{
303*4882a593Smuzhiyun 		struct snd_usx2y_substream *capsubs = usx2y->subs[SNDRV_PCM_STREAM_CAPTURE],
304*4882a593Smuzhiyun 			*playbacksubs = usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
305*4882a593Smuzhiyun 		if (capsubs->completed_urb &&
306*4882a593Smuzhiyun 		    atomic_read(&capsubs->state) >= STATE_PREPARED &&
307*4882a593Smuzhiyun 		    (playbacksubs->completed_urb ||
308*4882a593Smuzhiyun 		     atomic_read(&playbacksubs->state) < STATE_PREPARED)) {
309*4882a593Smuzhiyun 			if (!usx2y_usbframe_complete(capsubs, playbacksubs, urb->start_frame))
310*4882a593Smuzhiyun 				usx2y->wait_iso_frame += nr_of_packs();
311*4882a593Smuzhiyun 			else {
312*4882a593Smuzhiyun 				snd_printdd("\n");
313*4882a593Smuzhiyun 				usx2y_clients_stop(usx2y);
314*4882a593Smuzhiyun 			}
315*4882a593Smuzhiyun 		}
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
usx2y_urbs_set_complete(struct usx2ydev * usx2y,void (* complete)(struct urb *))319*4882a593Smuzhiyun static void usx2y_urbs_set_complete(struct usx2ydev * usx2y,
320*4882a593Smuzhiyun 				    void (*complete)(struct urb *))
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	int s, u;
323*4882a593Smuzhiyun 	for (s = 0; s < 4; s++) {
324*4882a593Smuzhiyun 		struct snd_usx2y_substream *subs = usx2y->subs[s];
325*4882a593Smuzhiyun 		if (NULL != subs)
326*4882a593Smuzhiyun 			for (u = 0; u < NRURBS; u++) {
327*4882a593Smuzhiyun 				struct urb * urb = subs->urb[u];
328*4882a593Smuzhiyun 				if (NULL != urb)
329*4882a593Smuzhiyun 					urb->complete = complete;
330*4882a593Smuzhiyun 			}
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun 
usx2y_subs_startup_finish(struct usx2ydev * usx2y)334*4882a593Smuzhiyun static void usx2y_subs_startup_finish(struct usx2ydev * usx2y)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	usx2y_urbs_set_complete(usx2y, i_usx2y_urb_complete);
337*4882a593Smuzhiyun 	usx2y->prepare_subs = NULL;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
i_usx2y_subs_startup(struct urb * urb)340*4882a593Smuzhiyun static void i_usx2y_subs_startup(struct urb *urb)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = urb->context;
343*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
344*4882a593Smuzhiyun 	struct snd_usx2y_substream *prepare_subs = usx2y->prepare_subs;
345*4882a593Smuzhiyun 	if (NULL != prepare_subs)
346*4882a593Smuzhiyun 		if (urb->start_frame == prepare_subs->urb[0]->start_frame) {
347*4882a593Smuzhiyun 			usx2y_subs_startup_finish(usx2y);
348*4882a593Smuzhiyun 			atomic_inc(&prepare_subs->state);
349*4882a593Smuzhiyun 			wake_up(&usx2y->prepare_wait_queue);
350*4882a593Smuzhiyun 		}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	i_usx2y_urb_complete(urb);
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
usx2y_subs_prepare(struct snd_usx2y_substream * subs)355*4882a593Smuzhiyun static void usx2y_subs_prepare(struct snd_usx2y_substream *subs)
356*4882a593Smuzhiyun {
357*4882a593Smuzhiyun 	snd_printdd("usx2y_substream_prepare(%p) ep=%i urb0=%p urb1=%p\n",
358*4882a593Smuzhiyun 		    subs, subs->endpoint, subs->urb[0], subs->urb[1]);
359*4882a593Smuzhiyun 	/* reset the pointer */
360*4882a593Smuzhiyun 	subs->hwptr = 0;
361*4882a593Smuzhiyun 	subs->hwptr_done = 0;
362*4882a593Smuzhiyun 	subs->transfer_done = 0;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 
usx2y_urb_release(struct urb ** urb,int free_tb)366*4882a593Smuzhiyun static void usx2y_urb_release(struct urb **urb, int free_tb)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	if (*urb) {
369*4882a593Smuzhiyun 		usb_kill_urb(*urb);
370*4882a593Smuzhiyun 		if (free_tb)
371*4882a593Smuzhiyun 			kfree((*urb)->transfer_buffer);
372*4882a593Smuzhiyun 		usb_free_urb(*urb);
373*4882a593Smuzhiyun 		*urb = NULL;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun }
376*4882a593Smuzhiyun /*
377*4882a593Smuzhiyun  * release a substreams urbs
378*4882a593Smuzhiyun  */
usx2y_urbs_release(struct snd_usx2y_substream * subs)379*4882a593Smuzhiyun static void usx2y_urbs_release(struct snd_usx2y_substream *subs)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	int i;
382*4882a593Smuzhiyun 	snd_printdd("usx2y_urbs_release() %i\n", subs->endpoint);
383*4882a593Smuzhiyun 	for (i = 0; i < NRURBS; i++)
384*4882a593Smuzhiyun 		usx2y_urb_release(subs->urb + i,
385*4882a593Smuzhiyun 				  subs != subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK]);
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	kfree(subs->tmpbuf);
388*4882a593Smuzhiyun 	subs->tmpbuf = NULL;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun /*
391*4882a593Smuzhiyun  * initialize a substream's urbs
392*4882a593Smuzhiyun  */
usx2y_urbs_allocate(struct snd_usx2y_substream * subs)393*4882a593Smuzhiyun static int usx2y_urbs_allocate(struct snd_usx2y_substream *subs)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun 	int i;
396*4882a593Smuzhiyun 	unsigned int pipe;
397*4882a593Smuzhiyun 	int is_playback = subs == subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
398*4882a593Smuzhiyun 	struct usb_device *dev = subs->usx2y->dev;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
401*4882a593Smuzhiyun 			usb_rcvisocpipe(dev, subs->endpoint);
402*4882a593Smuzhiyun 	subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
403*4882a593Smuzhiyun 	if (!subs->maxpacksize)
404*4882a593Smuzhiyun 		return -EINVAL;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	if (is_playback && NULL == subs->tmpbuf) {	/* allocate a temporary buffer for playback */
407*4882a593Smuzhiyun 		subs->tmpbuf = kcalloc(nr_of_packs(), subs->maxpacksize, GFP_KERNEL);
408*4882a593Smuzhiyun 		if (!subs->tmpbuf)
409*4882a593Smuzhiyun 			return -ENOMEM;
410*4882a593Smuzhiyun 	}
411*4882a593Smuzhiyun 	/* allocate and initialize data urbs */
412*4882a593Smuzhiyun 	for (i = 0; i < NRURBS; i++) {
413*4882a593Smuzhiyun 		struct urb **purb = subs->urb + i;
414*4882a593Smuzhiyun 		if (*purb) {
415*4882a593Smuzhiyun 			usb_kill_urb(*purb);
416*4882a593Smuzhiyun 			continue;
417*4882a593Smuzhiyun 		}
418*4882a593Smuzhiyun 		*purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
419*4882a593Smuzhiyun 		if (NULL == *purb) {
420*4882a593Smuzhiyun 			usx2y_urbs_release(subs);
421*4882a593Smuzhiyun 			return -ENOMEM;
422*4882a593Smuzhiyun 		}
423*4882a593Smuzhiyun 		if (!is_playback && !(*purb)->transfer_buffer) {
424*4882a593Smuzhiyun 			/* allocate a capture buffer per urb */
425*4882a593Smuzhiyun 			(*purb)->transfer_buffer =
426*4882a593Smuzhiyun 				kmalloc_array(subs->maxpacksize,
427*4882a593Smuzhiyun 					      nr_of_packs(), GFP_KERNEL);
428*4882a593Smuzhiyun 			if (NULL == (*purb)->transfer_buffer) {
429*4882a593Smuzhiyun 				usx2y_urbs_release(subs);
430*4882a593Smuzhiyun 				return -ENOMEM;
431*4882a593Smuzhiyun 			}
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 		(*purb)->dev = dev;
434*4882a593Smuzhiyun 		(*purb)->pipe = pipe;
435*4882a593Smuzhiyun 		(*purb)->number_of_packets = nr_of_packs();
436*4882a593Smuzhiyun 		(*purb)->context = subs;
437*4882a593Smuzhiyun 		(*purb)->interval = 1;
438*4882a593Smuzhiyun 		(*purb)->complete = i_usx2y_subs_startup;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 	return 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
usx2y_subs_startup(struct snd_usx2y_substream * subs)443*4882a593Smuzhiyun static void usx2y_subs_startup(struct snd_usx2y_substream *subs)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
446*4882a593Smuzhiyun 	usx2y->prepare_subs = subs;
447*4882a593Smuzhiyun 	subs->urb[0]->start_frame = -1;
448*4882a593Smuzhiyun 	wmb();
449*4882a593Smuzhiyun 	usx2y_urbs_set_complete(usx2y, i_usx2y_subs_startup);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun 
usx2y_urbs_start(struct snd_usx2y_substream * subs)452*4882a593Smuzhiyun static int usx2y_urbs_start(struct snd_usx2y_substream *subs)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	int i, err;
455*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if ((err = usx2y_urbs_allocate(subs)) < 0)
458*4882a593Smuzhiyun 		return err;
459*4882a593Smuzhiyun 	subs->completed_urb = NULL;
460*4882a593Smuzhiyun 	for (i = 0; i < 4; i++) {
461*4882a593Smuzhiyun 		struct snd_usx2y_substream *subs = usx2y->subs[i];
462*4882a593Smuzhiyun 		if (subs != NULL && atomic_read(&subs->state) >= STATE_PREPARED)
463*4882a593Smuzhiyun 			goto start;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun  start:
467*4882a593Smuzhiyun 	usx2y_subs_startup(subs);
468*4882a593Smuzhiyun 	for (i = 0; i < NRURBS; i++) {
469*4882a593Smuzhiyun 		struct urb *urb = subs->urb[i];
470*4882a593Smuzhiyun 		if (usb_pipein(urb->pipe)) {
471*4882a593Smuzhiyun 			unsigned long pack;
472*4882a593Smuzhiyun 			if (0 == i)
473*4882a593Smuzhiyun 				atomic_set(&subs->state, STATE_STARTING3);
474*4882a593Smuzhiyun 			urb->dev = usx2y->dev;
475*4882a593Smuzhiyun 			for (pack = 0; pack < nr_of_packs(); pack++) {
476*4882a593Smuzhiyun 				urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack;
477*4882a593Smuzhiyun 				urb->iso_frame_desc[pack].length = subs->maxpacksize;
478*4882a593Smuzhiyun 			}
479*4882a593Smuzhiyun 			urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
480*4882a593Smuzhiyun 			if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
481*4882a593Smuzhiyun 				snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
482*4882a593Smuzhiyun 				err = -EPIPE;
483*4882a593Smuzhiyun 				goto cleanup;
484*4882a593Smuzhiyun 			} else
485*4882a593Smuzhiyun 				if (i == 0)
486*4882a593Smuzhiyun 					usx2y->wait_iso_frame = urb->start_frame;
487*4882a593Smuzhiyun 			urb->transfer_flags = 0;
488*4882a593Smuzhiyun 		} else {
489*4882a593Smuzhiyun 			atomic_set(&subs->state, STATE_STARTING1);
490*4882a593Smuzhiyun 			break;
491*4882a593Smuzhiyun 		}
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 	err = 0;
494*4882a593Smuzhiyun 	wait_event(usx2y->prepare_wait_queue, NULL == usx2y->prepare_subs);
495*4882a593Smuzhiyun 	if (atomic_read(&subs->state) != STATE_PREPARED)
496*4882a593Smuzhiyun 		err = -EPIPE;
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun  cleanup:
499*4882a593Smuzhiyun 	if (err) {
500*4882a593Smuzhiyun 		usx2y_subs_startup_finish(usx2y);
501*4882a593Smuzhiyun 		usx2y_clients_stop(usx2y);		// something is completely wroong > stop evrything
502*4882a593Smuzhiyun 	}
503*4882a593Smuzhiyun 	return err;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun /*
507*4882a593Smuzhiyun  * return the current pcm pointer.  just return the hwptr_done value.
508*4882a593Smuzhiyun  */
snd_usx2y_pcm_pointer(struct snd_pcm_substream * substream)509*4882a593Smuzhiyun static snd_pcm_uframes_t snd_usx2y_pcm_pointer(struct snd_pcm_substream *substream)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = substream->runtime->private_data;
512*4882a593Smuzhiyun 	return subs->hwptr_done;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun /*
515*4882a593Smuzhiyun  * start/stop substream
516*4882a593Smuzhiyun  */
snd_usx2y_pcm_trigger(struct snd_pcm_substream * substream,int cmd)517*4882a593Smuzhiyun static int snd_usx2y_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = substream->runtime->private_data;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	switch (cmd) {
522*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_START:
523*4882a593Smuzhiyun 		snd_printdd("snd_usx2y_pcm_trigger(START)\n");
524*4882a593Smuzhiyun 		if (atomic_read(&subs->state) == STATE_PREPARED &&
525*4882a593Smuzhiyun 		    atomic_read(&subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE]->state) >= STATE_PREPARED) {
526*4882a593Smuzhiyun 			atomic_set(&subs->state, STATE_PRERUNNING);
527*4882a593Smuzhiyun 		} else {
528*4882a593Smuzhiyun 			snd_printdd("\n");
529*4882a593Smuzhiyun 			return -EPIPE;
530*4882a593Smuzhiyun 		}
531*4882a593Smuzhiyun 		break;
532*4882a593Smuzhiyun 	case SNDRV_PCM_TRIGGER_STOP:
533*4882a593Smuzhiyun 		snd_printdd("snd_usx2y_pcm_trigger(STOP)\n");
534*4882a593Smuzhiyun 		if (atomic_read(&subs->state) >= STATE_PRERUNNING)
535*4882a593Smuzhiyun 			atomic_set(&subs->state, STATE_PREPARED);
536*4882a593Smuzhiyun 		break;
537*4882a593Smuzhiyun 	default:
538*4882a593Smuzhiyun 		return -EINVAL;
539*4882a593Smuzhiyun 	}
540*4882a593Smuzhiyun 	return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun /*
545*4882a593Smuzhiyun  * allocate a buffer, setup samplerate
546*4882a593Smuzhiyun  *
547*4882a593Smuzhiyun  * so far we use a physically linear buffer although packetize transfer
548*4882a593Smuzhiyun  * doesn't need a continuous area.
549*4882a593Smuzhiyun  * if sg buffer is supported on the later version of alsa, we'll follow
550*4882a593Smuzhiyun  * that.
551*4882a593Smuzhiyun  */
552*4882a593Smuzhiyun static const struct s_c2
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	char c1, c2;
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 	setrate_44100[] =
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	{ 0x14, 0x08},	// this line sets 44100, well actually a little less
559*4882a593Smuzhiyun 	{ 0x18, 0x40},	// only tascam / frontier design knows the further lines .......
560*4882a593Smuzhiyun 	{ 0x18, 0x42},
561*4882a593Smuzhiyun 	{ 0x18, 0x45},
562*4882a593Smuzhiyun 	{ 0x18, 0x46},
563*4882a593Smuzhiyun 	{ 0x18, 0x48},
564*4882a593Smuzhiyun 	{ 0x18, 0x4A},
565*4882a593Smuzhiyun 	{ 0x18, 0x4C},
566*4882a593Smuzhiyun 	{ 0x18, 0x4E},
567*4882a593Smuzhiyun 	{ 0x18, 0x50},
568*4882a593Smuzhiyun 	{ 0x18, 0x52},
569*4882a593Smuzhiyun 	{ 0x18, 0x54},
570*4882a593Smuzhiyun 	{ 0x18, 0x56},
571*4882a593Smuzhiyun 	{ 0x18, 0x58},
572*4882a593Smuzhiyun 	{ 0x18, 0x5A},
573*4882a593Smuzhiyun 	{ 0x18, 0x5C},
574*4882a593Smuzhiyun 	{ 0x18, 0x5E},
575*4882a593Smuzhiyun 	{ 0x18, 0x60},
576*4882a593Smuzhiyun 	{ 0x18, 0x62},
577*4882a593Smuzhiyun 	{ 0x18, 0x64},
578*4882a593Smuzhiyun 	{ 0x18, 0x66},
579*4882a593Smuzhiyun 	{ 0x18, 0x68},
580*4882a593Smuzhiyun 	{ 0x18, 0x6A},
581*4882a593Smuzhiyun 	{ 0x18, 0x6C},
582*4882a593Smuzhiyun 	{ 0x18, 0x6E},
583*4882a593Smuzhiyun 	{ 0x18, 0x70},
584*4882a593Smuzhiyun 	{ 0x18, 0x72},
585*4882a593Smuzhiyun 	{ 0x18, 0x74},
586*4882a593Smuzhiyun 	{ 0x18, 0x76},
587*4882a593Smuzhiyun 	{ 0x18, 0x78},
588*4882a593Smuzhiyun 	{ 0x18, 0x7A},
589*4882a593Smuzhiyun 	{ 0x18, 0x7C},
590*4882a593Smuzhiyun 	{ 0x18, 0x7E}
591*4882a593Smuzhiyun };
592*4882a593Smuzhiyun static const struct s_c2 setrate_48000[] =
593*4882a593Smuzhiyun {
594*4882a593Smuzhiyun 	{ 0x14, 0x09},	// this line sets 48000, well actually a little less
595*4882a593Smuzhiyun 	{ 0x18, 0x40},	// only tascam / frontier design knows the further lines .......
596*4882a593Smuzhiyun 	{ 0x18, 0x42},
597*4882a593Smuzhiyun 	{ 0x18, 0x45},
598*4882a593Smuzhiyun 	{ 0x18, 0x46},
599*4882a593Smuzhiyun 	{ 0x18, 0x48},
600*4882a593Smuzhiyun 	{ 0x18, 0x4A},
601*4882a593Smuzhiyun 	{ 0x18, 0x4C},
602*4882a593Smuzhiyun 	{ 0x18, 0x4E},
603*4882a593Smuzhiyun 	{ 0x18, 0x50},
604*4882a593Smuzhiyun 	{ 0x18, 0x52},
605*4882a593Smuzhiyun 	{ 0x18, 0x54},
606*4882a593Smuzhiyun 	{ 0x18, 0x56},
607*4882a593Smuzhiyun 	{ 0x18, 0x58},
608*4882a593Smuzhiyun 	{ 0x18, 0x5A},
609*4882a593Smuzhiyun 	{ 0x18, 0x5C},
610*4882a593Smuzhiyun 	{ 0x18, 0x5E},
611*4882a593Smuzhiyun 	{ 0x18, 0x60},
612*4882a593Smuzhiyun 	{ 0x18, 0x62},
613*4882a593Smuzhiyun 	{ 0x18, 0x64},
614*4882a593Smuzhiyun 	{ 0x18, 0x66},
615*4882a593Smuzhiyun 	{ 0x18, 0x68},
616*4882a593Smuzhiyun 	{ 0x18, 0x6A},
617*4882a593Smuzhiyun 	{ 0x18, 0x6C},
618*4882a593Smuzhiyun 	{ 0x18, 0x6E},
619*4882a593Smuzhiyun 	{ 0x18, 0x70},
620*4882a593Smuzhiyun 	{ 0x18, 0x73},
621*4882a593Smuzhiyun 	{ 0x18, 0x74},
622*4882a593Smuzhiyun 	{ 0x18, 0x76},
623*4882a593Smuzhiyun 	{ 0x18, 0x78},
624*4882a593Smuzhiyun 	{ 0x18, 0x7A},
625*4882a593Smuzhiyun 	{ 0x18, 0x7C},
626*4882a593Smuzhiyun 	{ 0x18, 0x7E}
627*4882a593Smuzhiyun };
628*4882a593Smuzhiyun #define NOOF_SETRATE_URBS ARRAY_SIZE(setrate_48000)
629*4882a593Smuzhiyun 
i_usx2y_04int(struct urb * urb)630*4882a593Smuzhiyun static void i_usx2y_04int(struct urb *urb)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	struct usx2ydev *usx2y = urb->context;
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	if (urb->status)
635*4882a593Smuzhiyun 		snd_printk(KERN_ERR "snd_usx2y_04int() urb->status=%i\n", urb->status);
636*4882a593Smuzhiyun 	if (0 == --usx2y->us04->len)
637*4882a593Smuzhiyun 		wake_up(&usx2y->in04_wait_queue);
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun 
usx2y_rate_set(struct usx2ydev * usx2y,int rate)640*4882a593Smuzhiyun static int usx2y_rate_set(struct usx2ydev *usx2y, int rate)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun 	int			err = 0, i;
643*4882a593Smuzhiyun 	struct snd_usx2y_urb_seq	*us = NULL;
644*4882a593Smuzhiyun 	int			*usbdata = NULL;
645*4882a593Smuzhiyun 	const struct s_c2	*ra = rate == 48000 ? setrate_48000 : setrate_44100;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if (usx2y->rate != rate) {
648*4882a593Smuzhiyun 		us = kzalloc(sizeof(*us) + sizeof(struct urb*) * NOOF_SETRATE_URBS, GFP_KERNEL);
649*4882a593Smuzhiyun 		if (NULL == us) {
650*4882a593Smuzhiyun 			err = -ENOMEM;
651*4882a593Smuzhiyun 			goto cleanup;
652*4882a593Smuzhiyun 		}
653*4882a593Smuzhiyun 		usbdata = kmalloc_array(NOOF_SETRATE_URBS, sizeof(int),
654*4882a593Smuzhiyun 					GFP_KERNEL);
655*4882a593Smuzhiyun 		if (NULL == usbdata) {
656*4882a593Smuzhiyun 			err = -ENOMEM;
657*4882a593Smuzhiyun 			goto cleanup;
658*4882a593Smuzhiyun 		}
659*4882a593Smuzhiyun 		for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
660*4882a593Smuzhiyun 			if (NULL == (us->urb[i] = usb_alloc_urb(0, GFP_KERNEL))) {
661*4882a593Smuzhiyun 				err = -ENOMEM;
662*4882a593Smuzhiyun 				goto cleanup;
663*4882a593Smuzhiyun 			}
664*4882a593Smuzhiyun 			((char*)(usbdata + i))[0] = ra[i].c1;
665*4882a593Smuzhiyun 			((char*)(usbdata + i))[1] = ra[i].c2;
666*4882a593Smuzhiyun 			usb_fill_bulk_urb(us->urb[i], usx2y->dev, usb_sndbulkpipe(usx2y->dev, 4),
667*4882a593Smuzhiyun 					  usbdata + i, 2, i_usx2y_04int, usx2y);
668*4882a593Smuzhiyun 		}
669*4882a593Smuzhiyun 		err = usb_urb_ep_type_check(us->urb[0]);
670*4882a593Smuzhiyun 		if (err < 0)
671*4882a593Smuzhiyun 			goto cleanup;
672*4882a593Smuzhiyun 		us->submitted =	0;
673*4882a593Smuzhiyun 		us->len =	NOOF_SETRATE_URBS;
674*4882a593Smuzhiyun 		usx2y->us04 =	us;
675*4882a593Smuzhiyun 		wait_event_timeout(usx2y->in04_wait_queue, 0 == us->len, HZ);
676*4882a593Smuzhiyun 		usx2y->us04 =	NULL;
677*4882a593Smuzhiyun 		if (us->len)
678*4882a593Smuzhiyun 			err = -ENODEV;
679*4882a593Smuzhiyun 	cleanup:
680*4882a593Smuzhiyun 		if (us) {
681*4882a593Smuzhiyun 			us->submitted =	2*NOOF_SETRATE_URBS;
682*4882a593Smuzhiyun 			for (i = 0; i < NOOF_SETRATE_URBS; ++i) {
683*4882a593Smuzhiyun 				struct urb *urb = us->urb[i];
684*4882a593Smuzhiyun 				if (!urb)
685*4882a593Smuzhiyun 					continue;
686*4882a593Smuzhiyun 				if (urb->status) {
687*4882a593Smuzhiyun 					if (!err)
688*4882a593Smuzhiyun 						err = -ENODEV;
689*4882a593Smuzhiyun 					usb_kill_urb(urb);
690*4882a593Smuzhiyun 				}
691*4882a593Smuzhiyun 				usb_free_urb(urb);
692*4882a593Smuzhiyun 			}
693*4882a593Smuzhiyun 			usx2y->us04 = NULL;
694*4882a593Smuzhiyun 			kfree(usbdata);
695*4882a593Smuzhiyun 			kfree(us);
696*4882a593Smuzhiyun 			if (!err)
697*4882a593Smuzhiyun 				usx2y->rate = rate;
698*4882a593Smuzhiyun 		}
699*4882a593Smuzhiyun 	}
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	return err;
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 
usx2y_format_set(struct usx2ydev * usx2y,snd_pcm_format_t format)705*4882a593Smuzhiyun static int usx2y_format_set(struct usx2ydev *usx2y, snd_pcm_format_t format)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun 	int alternate, err;
708*4882a593Smuzhiyun 	struct list_head* p;
709*4882a593Smuzhiyun 	if (format == SNDRV_PCM_FORMAT_S24_3LE) {
710*4882a593Smuzhiyun 		alternate = 2;
711*4882a593Smuzhiyun 		usx2y->stride = 6;
712*4882a593Smuzhiyun 	} else {
713*4882a593Smuzhiyun 		alternate = 1;
714*4882a593Smuzhiyun 		usx2y->stride = 4;
715*4882a593Smuzhiyun 	}
716*4882a593Smuzhiyun 	list_for_each(p, &usx2y->midi_list) {
717*4882a593Smuzhiyun 		snd_usbmidi_input_stop(p);
718*4882a593Smuzhiyun 	}
719*4882a593Smuzhiyun 	usb_kill_urb(usx2y->in04_urb);
720*4882a593Smuzhiyun 	if ((err = usb_set_interface(usx2y->dev, 0, alternate))) {
721*4882a593Smuzhiyun 		snd_printk(KERN_ERR "usb_set_interface error \n");
722*4882a593Smuzhiyun 		return err;
723*4882a593Smuzhiyun 	}
724*4882a593Smuzhiyun 	usx2y->in04_urb->dev = usx2y->dev;
725*4882a593Smuzhiyun 	err = usb_submit_urb(usx2y->in04_urb, GFP_KERNEL);
726*4882a593Smuzhiyun 	list_for_each(p, &usx2y->midi_list) {
727*4882a593Smuzhiyun 		snd_usbmidi_input_start(p);
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	usx2y->format = format;
730*4882a593Smuzhiyun 	usx2y->rate = 0;
731*4882a593Smuzhiyun 	return err;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 
snd_usx2y_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * hw_params)735*4882a593Smuzhiyun static int snd_usx2y_pcm_hw_params(struct snd_pcm_substream *substream,
736*4882a593Smuzhiyun 				   struct snd_pcm_hw_params *hw_params)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	int			err = 0;
739*4882a593Smuzhiyun 	unsigned int		rate = params_rate(hw_params);
740*4882a593Smuzhiyun 	snd_pcm_format_t	format = params_format(hw_params);
741*4882a593Smuzhiyun 	struct snd_card *card = substream->pstr->pcm->card;
742*4882a593Smuzhiyun 	struct usx2ydev	*dev = usx2y(card);
743*4882a593Smuzhiyun 	int i;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	mutex_lock(&usx2y(card)->pcm_mutex);
746*4882a593Smuzhiyun 	snd_printdd("snd_usx2y_hw_params(%p, %p)\n", substream, hw_params);
747*4882a593Smuzhiyun 	/* all pcm substreams off one usx2y have to operate at the same
748*4882a593Smuzhiyun 	 * rate & format
749*4882a593Smuzhiyun 	 */
750*4882a593Smuzhiyun 	for (i = 0; i < dev->pcm_devs * 2; i++) {
751*4882a593Smuzhiyun 		struct snd_usx2y_substream *subs = dev->subs[i];
752*4882a593Smuzhiyun 		struct snd_pcm_substream *test_substream;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 		if (!subs)
755*4882a593Smuzhiyun 			continue;
756*4882a593Smuzhiyun 		test_substream = subs->pcm_substream;
757*4882a593Smuzhiyun 		if (!test_substream || test_substream == substream ||
758*4882a593Smuzhiyun 		    !test_substream->runtime)
759*4882a593Smuzhiyun 			continue;
760*4882a593Smuzhiyun 		if ((test_substream->runtime->format &&
761*4882a593Smuzhiyun 		     test_substream->runtime->format != format) ||
762*4882a593Smuzhiyun 		    (test_substream->runtime->rate &&
763*4882a593Smuzhiyun 		     test_substream->runtime->rate != rate)) {
764*4882a593Smuzhiyun 			err = -EINVAL;
765*4882a593Smuzhiyun 			goto error;
766*4882a593Smuzhiyun 		}
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun  error:
770*4882a593Smuzhiyun 	mutex_unlock(&usx2y(card)->pcm_mutex);
771*4882a593Smuzhiyun 	return err;
772*4882a593Smuzhiyun }
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun /*
775*4882a593Smuzhiyun  * free the buffer
776*4882a593Smuzhiyun  */
snd_usx2y_pcm_hw_free(struct snd_pcm_substream * substream)777*4882a593Smuzhiyun static int snd_usx2y_pcm_hw_free(struct snd_pcm_substream *substream)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
780*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = runtime->private_data;
781*4882a593Smuzhiyun 	mutex_lock(&subs->usx2y->pcm_mutex);
782*4882a593Smuzhiyun 	snd_printdd("snd_usx2y_hw_free(%p)\n", substream);
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
785*4882a593Smuzhiyun 		struct snd_usx2y_substream *cap_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
786*4882a593Smuzhiyun 		atomic_set(&subs->state, STATE_STOPPED);
787*4882a593Smuzhiyun 		usx2y_urbs_release(subs);
788*4882a593Smuzhiyun 		if (!cap_subs->pcm_substream ||
789*4882a593Smuzhiyun 		    !cap_subs->pcm_substream->runtime ||
790*4882a593Smuzhiyun 		    !cap_subs->pcm_substream->runtime->status ||
791*4882a593Smuzhiyun 		    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
792*4882a593Smuzhiyun 			atomic_set(&cap_subs->state, STATE_STOPPED);
793*4882a593Smuzhiyun 			usx2y_urbs_release(cap_subs);
794*4882a593Smuzhiyun 		}
795*4882a593Smuzhiyun 	} else {
796*4882a593Smuzhiyun 		struct snd_usx2y_substream *playback_subs = subs->usx2y->subs[SNDRV_PCM_STREAM_PLAYBACK];
797*4882a593Smuzhiyun 		if (atomic_read(&playback_subs->state) < STATE_PREPARED) {
798*4882a593Smuzhiyun 			atomic_set(&subs->state, STATE_STOPPED);
799*4882a593Smuzhiyun 			usx2y_urbs_release(subs);
800*4882a593Smuzhiyun 		}
801*4882a593Smuzhiyun 	}
802*4882a593Smuzhiyun 	mutex_unlock(&subs->usx2y->pcm_mutex);
803*4882a593Smuzhiyun 	return 0;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun /*
806*4882a593Smuzhiyun  * prepare callback
807*4882a593Smuzhiyun  *
808*4882a593Smuzhiyun  * set format and initialize urbs
809*4882a593Smuzhiyun  */
snd_usx2y_pcm_prepare(struct snd_pcm_substream * substream)810*4882a593Smuzhiyun static int snd_usx2y_pcm_prepare(struct snd_pcm_substream *substream)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
813*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = runtime->private_data;
814*4882a593Smuzhiyun 	struct usx2ydev *usx2y = subs->usx2y;
815*4882a593Smuzhiyun 	struct snd_usx2y_substream *capsubs = subs->usx2y->subs[SNDRV_PCM_STREAM_CAPTURE];
816*4882a593Smuzhiyun 	int err = 0;
817*4882a593Smuzhiyun 	snd_printdd("snd_usx2y_pcm_prepare(%p)\n", substream);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	mutex_lock(&usx2y->pcm_mutex);
820*4882a593Smuzhiyun 	usx2y_subs_prepare(subs);
821*4882a593Smuzhiyun // Start hardware streams
822*4882a593Smuzhiyun // SyncStream first....
823*4882a593Smuzhiyun 	if (atomic_read(&capsubs->state) < STATE_PREPARED) {
824*4882a593Smuzhiyun 		if (usx2y->format != runtime->format)
825*4882a593Smuzhiyun 			if ((err = usx2y_format_set(usx2y, runtime->format)) < 0)
826*4882a593Smuzhiyun 				goto up_prepare_mutex;
827*4882a593Smuzhiyun 		if (usx2y->rate != runtime->rate)
828*4882a593Smuzhiyun 			if ((err = usx2y_rate_set(usx2y, runtime->rate)) < 0)
829*4882a593Smuzhiyun 				goto up_prepare_mutex;
830*4882a593Smuzhiyun 		snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe");
831*4882a593Smuzhiyun 		if (0 > (err = usx2y_urbs_start(capsubs)))
832*4882a593Smuzhiyun 			goto up_prepare_mutex;
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	if (subs != capsubs && atomic_read(&subs->state) < STATE_PREPARED)
836*4882a593Smuzhiyun 		err = usx2y_urbs_start(subs);
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun  up_prepare_mutex:
839*4882a593Smuzhiyun 	mutex_unlock(&usx2y->pcm_mutex);
840*4882a593Smuzhiyun 	return err;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_usx2y_2c =
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
846*4882a593Smuzhiyun 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
847*4882a593Smuzhiyun 				 SNDRV_PCM_INFO_MMAP_VALID |
848*4882a593Smuzhiyun 				 SNDRV_PCM_INFO_BATCH),
849*4882a593Smuzhiyun 	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
850*4882a593Smuzhiyun 	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
851*4882a593Smuzhiyun 	.rate_min =                44100,
852*4882a593Smuzhiyun 	.rate_max =                48000,
853*4882a593Smuzhiyun 	.channels_min =            2,
854*4882a593Smuzhiyun 	.channels_max =            2,
855*4882a593Smuzhiyun 	.buffer_bytes_max =	(2*128*1024),
856*4882a593Smuzhiyun 	.period_bytes_min =	64,
857*4882a593Smuzhiyun 	.period_bytes_max =	(128*1024),
858*4882a593Smuzhiyun 	.periods_min =		2,
859*4882a593Smuzhiyun 	.periods_max =		1024,
860*4882a593Smuzhiyun 	.fifo_size =              0
861*4882a593Smuzhiyun };
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun 
snd_usx2y_pcm_open(struct snd_pcm_substream * substream)865*4882a593Smuzhiyun static int snd_usx2y_pcm_open(struct snd_pcm_substream *substream)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun 	struct snd_usx2y_substream	*subs = ((struct snd_usx2y_substream **)
868*4882a593Smuzhiyun 					 snd_pcm_substream_chip(substream))[substream->stream];
869*4882a593Smuzhiyun 	struct snd_pcm_runtime	*runtime = substream->runtime;
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 	if (subs->usx2y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS)
872*4882a593Smuzhiyun 		return -EBUSY;
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	runtime->hw = snd_usx2y_2c;
875*4882a593Smuzhiyun 	runtime->private_data = subs;
876*4882a593Smuzhiyun 	subs->pcm_substream = substream;
877*4882a593Smuzhiyun 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
878*4882a593Smuzhiyun 	return 0;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 
snd_usx2y_pcm_close(struct snd_pcm_substream * substream)883*4882a593Smuzhiyun static int snd_usx2y_pcm_close(struct snd_pcm_substream *substream)
884*4882a593Smuzhiyun {
885*4882a593Smuzhiyun 	struct snd_pcm_runtime *runtime = substream->runtime;
886*4882a593Smuzhiyun 	struct snd_usx2y_substream *subs = runtime->private_data;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	subs->pcm_substream = NULL;
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	return 0;
891*4882a593Smuzhiyun }
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun static const struct snd_pcm_ops snd_usx2y_pcm_ops =
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun 	.open =		snd_usx2y_pcm_open,
897*4882a593Smuzhiyun 	.close =	snd_usx2y_pcm_close,
898*4882a593Smuzhiyun 	.hw_params =	snd_usx2y_pcm_hw_params,
899*4882a593Smuzhiyun 	.hw_free =	snd_usx2y_pcm_hw_free,
900*4882a593Smuzhiyun 	.prepare =	snd_usx2y_pcm_prepare,
901*4882a593Smuzhiyun 	.trigger =	snd_usx2y_pcm_trigger,
902*4882a593Smuzhiyun 	.pointer =	snd_usx2y_pcm_pointer,
903*4882a593Smuzhiyun };
904*4882a593Smuzhiyun 
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun /*
907*4882a593Smuzhiyun  * free a usb stream instance
908*4882a593Smuzhiyun  */
usx2y_audio_stream_free(struct snd_usx2y_substream ** usx2y_substream)909*4882a593Smuzhiyun static void usx2y_audio_stream_free(struct snd_usx2y_substream **usx2y_substream)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun 	int stream;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	for_each_pcm_streams(stream) {
914*4882a593Smuzhiyun 		kfree(usx2y_substream[stream]);
915*4882a593Smuzhiyun 		usx2y_substream[stream] = NULL;
916*4882a593Smuzhiyun 	}
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun 
snd_usx2y_pcm_private_free(struct snd_pcm * pcm)919*4882a593Smuzhiyun static void snd_usx2y_pcm_private_free(struct snd_pcm *pcm)
920*4882a593Smuzhiyun {
921*4882a593Smuzhiyun 	struct snd_usx2y_substream **usx2y_stream = pcm->private_data;
922*4882a593Smuzhiyun 	if (usx2y_stream)
923*4882a593Smuzhiyun 		usx2y_audio_stream_free(usx2y_stream);
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun 
usx2y_audio_stream_new(struct snd_card * card,int playback_endpoint,int capture_endpoint)926*4882a593Smuzhiyun static int usx2y_audio_stream_new(struct snd_card *card, int playback_endpoint, int capture_endpoint)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun 	struct snd_pcm *pcm;
929*4882a593Smuzhiyun 	int err, i;
930*4882a593Smuzhiyun 	struct snd_usx2y_substream **usx2y_substream =
931*4882a593Smuzhiyun 		usx2y(card)->subs + 2 * usx2y(card)->pcm_devs;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun 	for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
934*4882a593Smuzhiyun 	     i <= SNDRV_PCM_STREAM_CAPTURE; ++i) {
935*4882a593Smuzhiyun 		usx2y_substream[i] = kzalloc(sizeof(struct snd_usx2y_substream), GFP_KERNEL);
936*4882a593Smuzhiyun 		if (!usx2y_substream[i])
937*4882a593Smuzhiyun 			return -ENOMEM;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 		usx2y_substream[i]->usx2y = usx2y(card);
940*4882a593Smuzhiyun 	}
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	if (playback_endpoint)
943*4882a593Smuzhiyun 		usx2y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint;
944*4882a593Smuzhiyun 	usx2y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usx2y(card)->pcm_devs,
947*4882a593Smuzhiyun 			  playback_endpoint ? 1 : 0, 1,
948*4882a593Smuzhiyun 			  &pcm);
949*4882a593Smuzhiyun 	if (err < 0) {
950*4882a593Smuzhiyun 		usx2y_audio_stream_free(usx2y_substream);
951*4882a593Smuzhiyun 		return err;
952*4882a593Smuzhiyun 	}
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	if (playback_endpoint)
955*4882a593Smuzhiyun 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usx2y_pcm_ops);
956*4882a593Smuzhiyun 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usx2y_pcm_ops);
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	pcm->private_data = usx2y_substream;
959*4882a593Smuzhiyun 	pcm->private_free = snd_usx2y_pcm_private_free;
960*4882a593Smuzhiyun 	pcm->info_flags = 0;
961*4882a593Smuzhiyun 
962*4882a593Smuzhiyun 	sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usx2y(card)->pcm_devs);
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	if (playback_endpoint) {
965*4882a593Smuzhiyun 		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
966*4882a593Smuzhiyun 					   SNDRV_DMA_TYPE_CONTINUOUS,
967*4882a593Smuzhiyun 					   NULL,
968*4882a593Smuzhiyun 					   64*1024, 128*1024);
969*4882a593Smuzhiyun 	}
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
972*4882a593Smuzhiyun 				   SNDRV_DMA_TYPE_CONTINUOUS,
973*4882a593Smuzhiyun 				   NULL,
974*4882a593Smuzhiyun 				   64*1024, 128*1024);
975*4882a593Smuzhiyun 	usx2y(card)->pcm_devs++;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 	return 0;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun /*
981*4882a593Smuzhiyun  * create a chip instance and set its names.
982*4882a593Smuzhiyun  */
usx2y_audio_create(struct snd_card * card)983*4882a593Smuzhiyun int usx2y_audio_create(struct snd_card *card)
984*4882a593Smuzhiyun {
985*4882a593Smuzhiyun 	int err = 0;
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 	INIT_LIST_HEAD(&usx2y(card)->pcm_list);
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	if (0 > (err = usx2y_audio_stream_new(card, 0xA, 0x8)))
990*4882a593Smuzhiyun 		return err;
991*4882a593Smuzhiyun 	if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) == USB_ID_US428)
992*4882a593Smuzhiyun 	     if (0 > (err = usx2y_audio_stream_new(card, 0, 0xA)))
993*4882a593Smuzhiyun 		     return err;
994*4882a593Smuzhiyun 	if (le16_to_cpu(usx2y(card)->dev->descriptor.idProduct) != USB_ID_US122)
995*4882a593Smuzhiyun 		err = usx2y_rate_set(usx2y(card), 44100);	// Lets us428 recognize output-volume settings, disturbs us122.
996*4882a593Smuzhiyun 	return err;
997*4882a593Smuzhiyun }
998