xref: /openbmc/linux/sound/usb/usx2y/usb_stream.c (revision 80b2b03b)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2030a07e4SKarsten Wiese /*
3030a07e4SKarsten Wiese  * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de>
4030a07e4SKarsten Wiese  */
5030a07e4SKarsten Wiese 
6030a07e4SKarsten Wiese #include <linux/usb.h>
75a0e3ad6STejun Heo #include <linux/gfp.h>
8030a07e4SKarsten Wiese 
9030a07e4SKarsten Wiese #include "usb_stream.h"
10030a07e4SKarsten Wiese 
11030a07e4SKarsten Wiese /*                             setup                                  */
12030a07e4SKarsten Wiese 
usb_stream_next_packet_size(struct usb_stream_kernel * sk)13a829dd5bSTakashi Iwai static unsigned int usb_stream_next_packet_size(struct usb_stream_kernel *sk)
14030a07e4SKarsten Wiese {
15030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
164c0a58efSTakashi Iwai 
17030a07e4SKarsten Wiese 	sk->out_phase_peeked = (sk->out_phase & 0xffff) + sk->freqn;
18030a07e4SKarsten Wiese 	return (sk->out_phase_peeked >> 16) * s->cfg.frame_size;
19030a07e4SKarsten Wiese }
20030a07e4SKarsten Wiese 
playback_prep_freqn(struct usb_stream_kernel * sk,struct urb * urb)21030a07e4SKarsten Wiese static void playback_prep_freqn(struct usb_stream_kernel *sk, struct urb *urb)
22030a07e4SKarsten Wiese {
23030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
24f600f6c4SKarsten Wiese 	int pack, lb = 0;
25030a07e4SKarsten Wiese 
26f600f6c4SKarsten Wiese 	for (pack = 0; pack < sk->n_o_ps; pack++) {
27f600f6c4SKarsten Wiese 		int l = usb_stream_next_packet_size(sk);
284c0a58efSTakashi Iwai 
29f600f6c4SKarsten Wiese 		if (s->idle_outsize + lb + l > s->period_size)
30030a07e4SKarsten Wiese 			goto check;
31030a07e4SKarsten Wiese 
32030a07e4SKarsten Wiese 		sk->out_phase = sk->out_phase_peeked;
33f600f6c4SKarsten Wiese 		urb->iso_frame_desc[pack].offset = lb;
34030a07e4SKarsten Wiese 		urb->iso_frame_desc[pack].length = l;
35f600f6c4SKarsten Wiese 		lb += l;
36030a07e4SKarsten Wiese 	}
37f600f6c4SKarsten Wiese 	snd_printdd(KERN_DEBUG "%i\n", lb);
38030a07e4SKarsten Wiese 
39030a07e4SKarsten Wiese check:
40030a07e4SKarsten Wiese 	urb->number_of_packets = pack;
41f600f6c4SKarsten Wiese 	urb->transfer_buffer_length = lb;
42f600f6c4SKarsten Wiese 	s->idle_outsize += lb - s->period_size;
43030a07e4SKarsten Wiese 	snd_printdd(KERN_DEBUG "idle=%i ul=%i ps=%i\n", s->idle_outsize,
44f600f6c4SKarsten Wiese 		    lb, s->period_size);
45030a07e4SKarsten Wiese }
46030a07e4SKarsten Wiese 
init_pipe_urbs(struct usb_stream_kernel * sk,unsigned int use_packsize,struct urb ** urbs,char * transfer,struct usb_device * dev,int pipe)47a829dd5bSTakashi Iwai static int init_pipe_urbs(struct usb_stream_kernel *sk,
48a829dd5bSTakashi Iwai 			  unsigned int use_packsize,
49030a07e4SKarsten Wiese 			  struct urb **urbs, char *transfer,
50030a07e4SKarsten Wiese 			  struct usb_device *dev, int pipe)
51030a07e4SKarsten Wiese {
52030a07e4SKarsten Wiese 	int u, p;
53030a07e4SKarsten Wiese 	int maxpacket = use_packsize ?
54*80b2b03bSVincent Mailhol 		use_packsize : usb_maxpacket(dev, pipe);
55030a07e4SKarsten Wiese 	int transfer_length = maxpacket * sk->n_o_ps;
56030a07e4SKarsten Wiese 
57030a07e4SKarsten Wiese 	for (u = 0; u < USB_STREAM_NURBS;
58030a07e4SKarsten Wiese 	     ++u, transfer += transfer_length) {
59030a07e4SKarsten Wiese 		struct urb *urb = urbs[u];
60030a07e4SKarsten Wiese 		struct usb_iso_packet_descriptor *desc;
614c0a58efSTakashi Iwai 
62030a07e4SKarsten Wiese 		urb->transfer_buffer = transfer;
63030a07e4SKarsten Wiese 		urb->dev = dev;
64030a07e4SKarsten Wiese 		urb->pipe = pipe;
65030a07e4SKarsten Wiese 		urb->number_of_packets = sk->n_o_ps;
66030a07e4SKarsten Wiese 		urb->context = sk;
67030a07e4SKarsten Wiese 		urb->interval = 1;
68030a07e4SKarsten Wiese 		if (usb_pipeout(pipe))
69030a07e4SKarsten Wiese 			continue;
70f9a1c372STakashi Iwai 		if (usb_urb_ep_type_check(urb))
71f9a1c372STakashi Iwai 			return -EINVAL;
72030a07e4SKarsten Wiese 
73030a07e4SKarsten Wiese 		urb->transfer_buffer_length = transfer_length;
74030a07e4SKarsten Wiese 		desc = urb->iso_frame_desc;
75030a07e4SKarsten Wiese 		desc->offset = 0;
76030a07e4SKarsten Wiese 		desc->length = maxpacket;
77030a07e4SKarsten Wiese 		for (p = 1; p < sk->n_o_ps; ++p) {
78030a07e4SKarsten Wiese 			desc[p].offset = desc[p - 1].offset + maxpacket;
79030a07e4SKarsten Wiese 			desc[p].length = maxpacket;
80030a07e4SKarsten Wiese 		}
81030a07e4SKarsten Wiese 	}
82f9a1c372STakashi Iwai 
83f9a1c372STakashi Iwai 	return 0;
84030a07e4SKarsten Wiese }
85030a07e4SKarsten Wiese 
init_urbs(struct usb_stream_kernel * sk,unsigned int use_packsize,struct usb_device * dev,int in_pipe,int out_pipe)86a829dd5bSTakashi Iwai static int init_urbs(struct usb_stream_kernel *sk, unsigned int use_packsize,
87030a07e4SKarsten Wiese 		     struct usb_device *dev, int in_pipe, int out_pipe)
88030a07e4SKarsten Wiese {
89030a07e4SKarsten Wiese 	struct usb_stream	*s = sk->s;
904c0a58efSTakashi Iwai 	char			*indata =
914c0a58efSTakashi Iwai 		(char *)s + sizeof(*s) + sizeof(struct usb_stream_packet) * s->inpackets;
92030a07e4SKarsten Wiese 	int			u;
93030a07e4SKarsten Wiese 
94030a07e4SKarsten Wiese 	for (u = 0; u < USB_STREAM_NURBS; ++u) {
95030a07e4SKarsten Wiese 		sk->inurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
96a2c6433eSAditya Pakki 		if (!sk->inurb[u])
97a2c6433eSAditya Pakki 			return -ENOMEM;
98a2c6433eSAditya Pakki 
99030a07e4SKarsten Wiese 		sk->outurb[u] = usb_alloc_urb(sk->n_o_ps, GFP_KERNEL);
100a2c6433eSAditya Pakki 		if (!sk->outurb[u])
101a2c6433eSAditya Pakki 			return -ENOMEM;
102030a07e4SKarsten Wiese 	}
103030a07e4SKarsten Wiese 
104f9a1c372STakashi Iwai 	if (init_pipe_urbs(sk, use_packsize, sk->inurb, indata, dev, in_pipe) ||
105030a07e4SKarsten Wiese 	    init_pipe_urbs(sk, use_packsize, sk->outurb, sk->write_page, dev,
106f9a1c372STakashi Iwai 			   out_pipe))
107f9a1c372STakashi Iwai 		return -EINVAL;
108f9a1c372STakashi Iwai 
109f9a1c372STakashi Iwai 	return 0;
110030a07e4SKarsten Wiese }
111030a07e4SKarsten Wiese 
112030a07e4SKarsten Wiese /*
113030a07e4SKarsten Wiese  * convert a sampling rate into our full speed format (fs/1000 in Q16.16)
114030a07e4SKarsten Wiese  * this will overflow at approx 524 kHz
115030a07e4SKarsten Wiese  */
get_usb_full_speed_rate(unsigned int rate)116a829dd5bSTakashi Iwai static inline unsigned int get_usb_full_speed_rate(unsigned int rate)
117030a07e4SKarsten Wiese {
118030a07e4SKarsten Wiese 	return ((rate << 13) + 62) / 125;
119030a07e4SKarsten Wiese }
120030a07e4SKarsten Wiese 
121030a07e4SKarsten Wiese /*
122030a07e4SKarsten Wiese  * convert a sampling rate into USB high speed format (fs/8000 in Q16.16)
123030a07e4SKarsten Wiese  * this will overflow at approx 4 MHz
124030a07e4SKarsten Wiese  */
get_usb_high_speed_rate(unsigned int rate)125a829dd5bSTakashi Iwai static inline unsigned int get_usb_high_speed_rate(unsigned int rate)
126030a07e4SKarsten Wiese {
127030a07e4SKarsten Wiese 	return ((rate << 10) + 62) / 125;
128030a07e4SKarsten Wiese }
129030a07e4SKarsten Wiese 
usb_stream_free(struct usb_stream_kernel * sk)130030a07e4SKarsten Wiese void usb_stream_free(struct usb_stream_kernel *sk)
131030a07e4SKarsten Wiese {
132030a07e4SKarsten Wiese 	struct usb_stream *s;
133a829dd5bSTakashi Iwai 	unsigned int u;
134030a07e4SKarsten Wiese 
135030a07e4SKarsten Wiese 	for (u = 0; u < USB_STREAM_NURBS; ++u) {
136030a07e4SKarsten Wiese 		usb_free_urb(sk->inurb[u]);
137030a07e4SKarsten Wiese 		sk->inurb[u] = NULL;
138030a07e4SKarsten Wiese 		usb_free_urb(sk->outurb[u]);
139030a07e4SKarsten Wiese 		sk->outurb[u] = NULL;
140030a07e4SKarsten Wiese 	}
141030a07e4SKarsten Wiese 
142030a07e4SKarsten Wiese 	s = sk->s;
143030a07e4SKarsten Wiese 	if (!s)
144030a07e4SKarsten Wiese 		return;
145030a07e4SKarsten Wiese 
146cae0cf65STakashi Iwai 	if (sk->write_page) {
14736b8defcSTakashi Iwai 		free_pages_exact(sk->write_page, s->write_size);
148030a07e4SKarsten Wiese 		sk->write_page = NULL;
149cae0cf65STakashi Iwai 	}
150cae0cf65STakashi Iwai 
15136b8defcSTakashi Iwai 	free_pages_exact(s, s->read_size);
152030a07e4SKarsten Wiese 	sk->s = NULL;
153030a07e4SKarsten Wiese }
154030a07e4SKarsten Wiese 
usb_stream_new(struct usb_stream_kernel * sk,struct usb_device * dev,unsigned int in_endpoint,unsigned int out_endpoint,unsigned int sample_rate,unsigned int use_packsize,unsigned int period_frames,unsigned int frame_size)155030a07e4SKarsten Wiese struct usb_stream *usb_stream_new(struct usb_stream_kernel *sk,
156030a07e4SKarsten Wiese 				  struct usb_device *dev,
157a829dd5bSTakashi Iwai 				  unsigned int in_endpoint,
158a829dd5bSTakashi Iwai 				  unsigned int out_endpoint,
159a829dd5bSTakashi Iwai 				  unsigned int sample_rate,
160a829dd5bSTakashi Iwai 				  unsigned int use_packsize,
161a829dd5bSTakashi Iwai 				  unsigned int period_frames,
162a829dd5bSTakashi Iwai 				  unsigned int frame_size)
163030a07e4SKarsten Wiese {
164030a07e4SKarsten Wiese 	int packets, max_packsize;
165030a07e4SKarsten Wiese 	int in_pipe, out_pipe;
166030a07e4SKarsten Wiese 	int read_size = sizeof(struct usb_stream);
167030a07e4SKarsten Wiese 	int write_size;
168030a07e4SKarsten Wiese 	int usb_frames = dev->speed == USB_SPEED_HIGH ? 8000 : 1000;
169030a07e4SKarsten Wiese 
170030a07e4SKarsten Wiese 	in_pipe = usb_rcvisocpipe(dev, in_endpoint);
171030a07e4SKarsten Wiese 	out_pipe = usb_sndisocpipe(dev, out_endpoint);
172030a07e4SKarsten Wiese 
173030a07e4SKarsten Wiese 	max_packsize = use_packsize ?
174*80b2b03bSVincent Mailhol 		use_packsize : usb_maxpacket(dev, in_pipe);
175030a07e4SKarsten Wiese 
176030a07e4SKarsten Wiese 	/*
177030a07e4SKarsten Wiese 		t_period = period_frames / sample_rate
178030a07e4SKarsten Wiese 		iso_packs = t_period / t_iso_frame
179030a07e4SKarsten Wiese 			= (period_frames / sample_rate) * (1 / t_iso_frame)
180030a07e4SKarsten Wiese 	*/
181030a07e4SKarsten Wiese 
182030a07e4SKarsten Wiese 	packets = period_frames * usb_frames / sample_rate + 1;
183030a07e4SKarsten Wiese 
184030a07e4SKarsten Wiese 	if (dev->speed == USB_SPEED_HIGH)
185030a07e4SKarsten Wiese 		packets = (packets + 7) & ~7;
186030a07e4SKarsten Wiese 
187030a07e4SKarsten Wiese 	read_size += packets * USB_STREAM_URBDEPTH *
188030a07e4SKarsten Wiese 		(max_packsize + sizeof(struct usb_stream_packet));
189030a07e4SKarsten Wiese 
190*80b2b03bSVincent Mailhol 	max_packsize = usb_maxpacket(dev, out_pipe);
191030a07e4SKarsten Wiese 	write_size = max_packsize * packets * USB_STREAM_URBDEPTH;
192030a07e4SKarsten Wiese 
193030a07e4SKarsten Wiese 	if (read_size >= 256*PAGE_SIZE || write_size >= 256*PAGE_SIZE) {
194030a07e4SKarsten Wiese 		snd_printk(KERN_WARNING "a size exceeds 128*PAGE_SIZE\n");
195030a07e4SKarsten Wiese 		goto out;
196030a07e4SKarsten Wiese 	}
197030a07e4SKarsten Wiese 
19836b8defcSTakashi Iwai 	sk->s = alloc_pages_exact(read_size,
19936b8defcSTakashi Iwai 				  GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
200030a07e4SKarsten Wiese 	if (!sk->s) {
20136b8defcSTakashi Iwai 		pr_warn("us122l: couldn't allocate read buffer\n");
202030a07e4SKarsten Wiese 		goto out;
203030a07e4SKarsten Wiese 	}
204030a07e4SKarsten Wiese 	sk->s->cfg.version = USB_STREAM_INTERFACE_VERSION;
205030a07e4SKarsten Wiese 
206030a07e4SKarsten Wiese 	sk->s->read_size = read_size;
207030a07e4SKarsten Wiese 
208030a07e4SKarsten Wiese 	sk->s->cfg.sample_rate = sample_rate;
209030a07e4SKarsten Wiese 	sk->s->cfg.frame_size = frame_size;
210030a07e4SKarsten Wiese 	sk->n_o_ps = packets;
211030a07e4SKarsten Wiese 	sk->s->inpackets = packets * USB_STREAM_URBDEPTH;
212030a07e4SKarsten Wiese 	sk->s->cfg.period_frames = period_frames;
213030a07e4SKarsten Wiese 	sk->s->period_size = frame_size * period_frames;
214030a07e4SKarsten Wiese 
215030a07e4SKarsten Wiese 	sk->s->write_size = write_size;
216030a07e4SKarsten Wiese 
21736b8defcSTakashi Iwai 	sk->write_page = alloc_pages_exact(write_size,
21836b8defcSTakashi Iwai 					   GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN);
219030a07e4SKarsten Wiese 	if (!sk->write_page) {
22036b8defcSTakashi Iwai 		pr_warn("us122l: couldn't allocate write buffer\n");
221030a07e4SKarsten Wiese 		usb_stream_free(sk);
222030a07e4SKarsten Wiese 		return NULL;
223030a07e4SKarsten Wiese 	}
224030a07e4SKarsten Wiese 
225030a07e4SKarsten Wiese 	/* calculate the frequency in 16.16 format */
226030a07e4SKarsten Wiese 	if (dev->speed == USB_SPEED_FULL)
227030a07e4SKarsten Wiese 		sk->freqn = get_usb_full_speed_rate(sample_rate);
228030a07e4SKarsten Wiese 	else
229030a07e4SKarsten Wiese 		sk->freqn = get_usb_high_speed_rate(sample_rate);
230030a07e4SKarsten Wiese 
231f9a1c372STakashi Iwai 	if (init_urbs(sk, use_packsize, dev, in_pipe, out_pipe) < 0) {
232f9a1c372STakashi Iwai 		usb_stream_free(sk);
233f9a1c372STakashi Iwai 		return NULL;
234f9a1c372STakashi Iwai 	}
235f9a1c372STakashi Iwai 
236030a07e4SKarsten Wiese 	sk->s->state = usb_stream_stopped;
237030a07e4SKarsten Wiese out:
238030a07e4SKarsten Wiese 	return sk->s;
239030a07e4SKarsten Wiese }
240030a07e4SKarsten Wiese 
241030a07e4SKarsten Wiese /*                             start                                  */
242030a07e4SKarsten Wiese 
balance_check(struct usb_stream_kernel * sk,struct urb * urb)243030a07e4SKarsten Wiese static bool balance_check(struct usb_stream_kernel *sk, struct urb *urb)
244030a07e4SKarsten Wiese {
245030a07e4SKarsten Wiese 	bool r;
2464c0a58efSTakashi Iwai 
247030a07e4SKarsten Wiese 	if (unlikely(urb->status)) {
248030a07e4SKarsten Wiese 		if (urb->status != -ESHUTDOWN && urb->status != -ENOENT)
249030a07e4SKarsten Wiese 			snd_printk(KERN_WARNING "status=%i\n", urb->status);
250030a07e4SKarsten Wiese 		sk->iso_frame_balance = 0x7FFFFFFF;
251030a07e4SKarsten Wiese 		return false;
252030a07e4SKarsten Wiese 	}
253030a07e4SKarsten Wiese 	r = sk->iso_frame_balance == 0;
254030a07e4SKarsten Wiese 	if (!r)
255030a07e4SKarsten Wiese 		sk->i_urb = urb;
256030a07e4SKarsten Wiese 	return r;
257030a07e4SKarsten Wiese }
258030a07e4SKarsten Wiese 
balance_playback(struct usb_stream_kernel * sk,struct urb * urb)259030a07e4SKarsten Wiese static bool balance_playback(struct usb_stream_kernel *sk, struct urb *urb)
260030a07e4SKarsten Wiese {
261030a07e4SKarsten Wiese 	sk->iso_frame_balance += urb->number_of_packets;
262030a07e4SKarsten Wiese 	return balance_check(sk, urb);
263030a07e4SKarsten Wiese }
264030a07e4SKarsten Wiese 
balance_capture(struct usb_stream_kernel * sk,struct urb * urb)265030a07e4SKarsten Wiese static bool balance_capture(struct usb_stream_kernel *sk, struct urb *urb)
266030a07e4SKarsten Wiese {
267030a07e4SKarsten Wiese 	sk->iso_frame_balance -= urb->number_of_packets;
268030a07e4SKarsten Wiese 	return balance_check(sk, urb);
269030a07e4SKarsten Wiese }
270030a07e4SKarsten Wiese 
subs_set_complete(struct urb ** urbs,void (* complete)(struct urb *))271030a07e4SKarsten Wiese static void subs_set_complete(struct urb **urbs, void (*complete)(struct urb *))
272030a07e4SKarsten Wiese {
273030a07e4SKarsten Wiese 	int u;
274030a07e4SKarsten Wiese 
275030a07e4SKarsten Wiese 	for (u = 0; u < USB_STREAM_NURBS; u++) {
276030a07e4SKarsten Wiese 		struct urb *urb = urbs[u];
2774c0a58efSTakashi Iwai 
278030a07e4SKarsten Wiese 		urb->complete = complete;
279030a07e4SKarsten Wiese 	}
280030a07e4SKarsten Wiese }
281030a07e4SKarsten Wiese 
usb_stream_prepare_playback(struct usb_stream_kernel * sk,struct urb * inurb)282acc42165SRoel Kluin static int usb_stream_prepare_playback(struct usb_stream_kernel *sk,
283acc42165SRoel Kluin 		struct urb *inurb)
284030a07e4SKarsten Wiese {
285030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
286030a07e4SKarsten Wiese 	struct urb *io;
287030a07e4SKarsten Wiese 	struct usb_iso_packet_descriptor *id, *od;
288f600f6c4SKarsten Wiese 	int p = 0, lb = 0, l = 0;
289030a07e4SKarsten Wiese 
290030a07e4SKarsten Wiese 	io = sk->idle_outurb;
291030a07e4SKarsten Wiese 	od = io->iso_frame_desc;
292030a07e4SKarsten Wiese 
293f600f6c4SKarsten Wiese 	for (; s->sync_packet < 0; ++p, ++s->sync_packet) {
294030a07e4SKarsten Wiese 		struct urb *ii = sk->completed_inurb;
2954c0a58efSTakashi Iwai 
296030a07e4SKarsten Wiese 		id = ii->iso_frame_desc +
297030a07e4SKarsten Wiese 			ii->number_of_packets + s->sync_packet;
298030a07e4SKarsten Wiese 		l = id->actual_length;
299030a07e4SKarsten Wiese 
300030a07e4SKarsten Wiese 		od[p].length = l;
301f600f6c4SKarsten Wiese 		od[p].offset = lb;
302f600f6c4SKarsten Wiese 		lb += l;
303030a07e4SKarsten Wiese 	}
304030a07e4SKarsten Wiese 
305030a07e4SKarsten Wiese 	for (;
306030a07e4SKarsten Wiese 	     s->sync_packet < inurb->number_of_packets && p < sk->n_o_ps;
307030a07e4SKarsten Wiese 	     ++p, ++s->sync_packet) {
308030a07e4SKarsten Wiese 		l = inurb->iso_frame_desc[s->sync_packet].actual_length;
309030a07e4SKarsten Wiese 
310f600f6c4SKarsten Wiese 		if (s->idle_outsize + lb + l > s->period_size)
311030a07e4SKarsten Wiese 			goto check_ok;
312030a07e4SKarsten Wiese 
313030a07e4SKarsten Wiese 		od[p].length = l;
314f600f6c4SKarsten Wiese 		od[p].offset = lb;
315f600f6c4SKarsten Wiese 		lb += l;
316030a07e4SKarsten Wiese 	}
317030a07e4SKarsten Wiese 
318030a07e4SKarsten Wiese check_ok:
319030a07e4SKarsten Wiese 	s->sync_packet -= inurb->number_of_packets;
320f600f6c4SKarsten Wiese 	if (unlikely(s->sync_packet < -2 || s->sync_packet > 0)) {
321030a07e4SKarsten Wiese 		snd_printk(KERN_WARNING "invalid sync_packet = %i;"
322030a07e4SKarsten Wiese 			   " p=%i nop=%i %i %x %x %x > %x\n",
323030a07e4SKarsten Wiese 			   s->sync_packet, p, inurb->number_of_packets,
324f600f6c4SKarsten Wiese 			   s->idle_outsize + lb + l,
325f600f6c4SKarsten Wiese 			   s->idle_outsize, lb,  l,
326030a07e4SKarsten Wiese 			   s->period_size);
327030a07e4SKarsten Wiese 		return -1;
328030a07e4SKarsten Wiese 	}
329f600f6c4SKarsten Wiese 	if (unlikely(lb % s->cfg.frame_size)) {
330030a07e4SKarsten Wiese 		snd_printk(KERN_WARNING"invalid outsize = %i\n",
331f600f6c4SKarsten Wiese 			   lb);
332030a07e4SKarsten Wiese 		return -1;
333030a07e4SKarsten Wiese 	}
334f600f6c4SKarsten Wiese 	s->idle_outsize += lb - s->period_size;
335030a07e4SKarsten Wiese 	io->number_of_packets = p;
336f600f6c4SKarsten Wiese 	io->transfer_buffer_length = lb;
337f600f6c4SKarsten Wiese 	if (s->idle_outsize <= 0)
338f600f6c4SKarsten Wiese 		return 0;
339f600f6c4SKarsten Wiese 
340030a07e4SKarsten Wiese 	snd_printk(KERN_WARNING "idle=%i\n", s->idle_outsize);
341030a07e4SKarsten Wiese 	return -1;
342030a07e4SKarsten Wiese }
343030a07e4SKarsten Wiese 
prepare_inurb(int number_of_packets,struct urb * iu)344030a07e4SKarsten Wiese static void prepare_inurb(int number_of_packets, struct urb *iu)
345030a07e4SKarsten Wiese {
346030a07e4SKarsten Wiese 	struct usb_iso_packet_descriptor *id;
347030a07e4SKarsten Wiese 	int p;
348030a07e4SKarsten Wiese 
349030a07e4SKarsten Wiese 	iu->number_of_packets = number_of_packets;
350030a07e4SKarsten Wiese 	id = iu->iso_frame_desc;
351030a07e4SKarsten Wiese 	id->offset = 0;
352030a07e4SKarsten Wiese 	for (p = 0; p < iu->number_of_packets - 1; ++p)
353030a07e4SKarsten Wiese 		id[p + 1].offset = id[p].offset + id[p].length;
354030a07e4SKarsten Wiese 
355030a07e4SKarsten Wiese 	iu->transfer_buffer_length =
356030a07e4SKarsten Wiese 		id[0].length * iu->number_of_packets;
357030a07e4SKarsten Wiese }
358030a07e4SKarsten Wiese 
submit_urbs(struct usb_stream_kernel * sk,struct urb * inurb,struct urb * outurb)359030a07e4SKarsten Wiese static int submit_urbs(struct usb_stream_kernel *sk,
360030a07e4SKarsten Wiese 		       struct urb *inurb, struct urb *outurb)
361030a07e4SKarsten Wiese {
362030a07e4SKarsten Wiese 	int err;
3634c0a58efSTakashi Iwai 
364030a07e4SKarsten Wiese 	prepare_inurb(sk->idle_outurb->number_of_packets, sk->idle_inurb);
365030a07e4SKarsten Wiese 	err = usb_submit_urb(sk->idle_inurb, GFP_ATOMIC);
366d2d97708SMarkus Elfring 	if (err < 0)
367d2d97708SMarkus Elfring 		goto report_failure;
368d2d97708SMarkus Elfring 
369030a07e4SKarsten Wiese 	sk->idle_inurb = sk->completed_inurb;
370030a07e4SKarsten Wiese 	sk->completed_inurb = inurb;
371030a07e4SKarsten Wiese 	err = usb_submit_urb(sk->idle_outurb, GFP_ATOMIC);
372d2d97708SMarkus Elfring 	if (err < 0)
373d2d97708SMarkus Elfring 		goto report_failure;
374d2d97708SMarkus Elfring 
375030a07e4SKarsten Wiese 	sk->idle_outurb = sk->completed_outurb;
376030a07e4SKarsten Wiese 	sk->completed_outurb = outurb;
377030a07e4SKarsten Wiese 	return 0;
378d2d97708SMarkus Elfring 
379d2d97708SMarkus Elfring report_failure:
380d2d97708SMarkus Elfring 	snd_printk(KERN_ERR "%i\n", err);
381d2d97708SMarkus Elfring 	return err;
382030a07e4SKarsten Wiese }
383030a07e4SKarsten Wiese 
384030a07e4SKarsten Wiese #ifdef DEBUG_LOOP_BACK
385030a07e4SKarsten Wiese /*
386030a07e4SKarsten Wiese   This loop_back() shows how to read/write the period data.
387030a07e4SKarsten Wiese  */
loop_back(struct usb_stream * s)388030a07e4SKarsten Wiese static void loop_back(struct usb_stream *s)
389030a07e4SKarsten Wiese {
390030a07e4SKarsten Wiese 	char *i, *o;
391030a07e4SKarsten Wiese 	int il, ol, l, p;
392030a07e4SKarsten Wiese 	struct urb *iu;
393030a07e4SKarsten Wiese 	struct usb_iso_packet_descriptor *id;
394030a07e4SKarsten Wiese 
395030a07e4SKarsten Wiese 	o = s->playback1st_to;
396030a07e4SKarsten Wiese 	ol = s->playback1st_size;
397030a07e4SKarsten Wiese 	l = 0;
398030a07e4SKarsten Wiese 
399030a07e4SKarsten Wiese 	if (s->insplit_pack >= 0) {
400030a07e4SKarsten Wiese 		iu = sk->idle_inurb;
401030a07e4SKarsten Wiese 		id = iu->iso_frame_desc;
402030a07e4SKarsten Wiese 		p = s->insplit_pack;
403030a07e4SKarsten Wiese 	} else
404030a07e4SKarsten Wiese 		goto second;
405030a07e4SKarsten Wiese loop:
406030a07e4SKarsten Wiese 	for (; p < iu->number_of_packets && l < s->period_size; ++p) {
407030a07e4SKarsten Wiese 		i = iu->transfer_buffer + id[p].offset;
408030a07e4SKarsten Wiese 		il = id[p].actual_length;
409030a07e4SKarsten Wiese 		if (l + il > s->period_size)
410030a07e4SKarsten Wiese 			il = s->period_size - l;
411030a07e4SKarsten Wiese 		if (il <= ol) {
412030a07e4SKarsten Wiese 			memcpy(o, i, il);
413030a07e4SKarsten Wiese 			o += il;
414030a07e4SKarsten Wiese 			ol -= il;
415030a07e4SKarsten Wiese 		} else {
416030a07e4SKarsten Wiese 			memcpy(o, i, ol);
417030a07e4SKarsten Wiese 			singen_6pack(o, ol);
418030a07e4SKarsten Wiese 			o = s->playback_to;
419030a07e4SKarsten Wiese 			memcpy(o, i + ol, il - ol);
420030a07e4SKarsten Wiese 			o += il - ol;
421030a07e4SKarsten Wiese 			ol = s->period_size - s->playback1st_size;
422030a07e4SKarsten Wiese 		}
423030a07e4SKarsten Wiese 		l += il;
424030a07e4SKarsten Wiese 	}
425030a07e4SKarsten Wiese 	if (iu == sk->completed_inurb) {
426030a07e4SKarsten Wiese 		if (l != s->period_size)
427030a07e4SKarsten Wiese 			printk(KERN_DEBUG"%s:%i %i\n", __func__, __LINE__,
428030a07e4SKarsten Wiese 			       l/(int)s->cfg.frame_size);
429030a07e4SKarsten Wiese 
430030a07e4SKarsten Wiese 		return;
431030a07e4SKarsten Wiese 	}
432030a07e4SKarsten Wiese second:
433030a07e4SKarsten Wiese 	iu = sk->completed_inurb;
434030a07e4SKarsten Wiese 	id = iu->iso_frame_desc;
435030a07e4SKarsten Wiese 	p = 0;
436030a07e4SKarsten Wiese 	goto loop;
437030a07e4SKarsten Wiese 
438030a07e4SKarsten Wiese }
439030a07e4SKarsten Wiese #else
loop_back(struct usb_stream * s)440030a07e4SKarsten Wiese static void loop_back(struct usb_stream *s)
441030a07e4SKarsten Wiese {
442030a07e4SKarsten Wiese }
443030a07e4SKarsten Wiese #endif
444030a07e4SKarsten Wiese 
stream_idle(struct usb_stream_kernel * sk,struct urb * inurb,struct urb * outurb)445030a07e4SKarsten Wiese static void stream_idle(struct usb_stream_kernel *sk,
446030a07e4SKarsten Wiese 			struct urb *inurb, struct urb *outurb)
447030a07e4SKarsten Wiese {
448030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
449030a07e4SKarsten Wiese 	int l, p;
450030a07e4SKarsten Wiese 	int insize = s->idle_insize;
451030a07e4SKarsten Wiese 	int urb_size = 0;
452030a07e4SKarsten Wiese 
453030a07e4SKarsten Wiese 	s->inpacket_split = s->next_inpacket_split;
454030a07e4SKarsten Wiese 	s->inpacket_split_at = s->next_inpacket_split_at;
455030a07e4SKarsten Wiese 	s->next_inpacket_split = -1;
456030a07e4SKarsten Wiese 	s->next_inpacket_split_at = 0;
457030a07e4SKarsten Wiese 
458030a07e4SKarsten Wiese 	for (p = 0; p < inurb->number_of_packets; ++p) {
459030a07e4SKarsten Wiese 		struct usb_iso_packet_descriptor *id = inurb->iso_frame_desc;
4604c0a58efSTakashi Iwai 
461030a07e4SKarsten Wiese 		l = id[p].actual_length;
462030a07e4SKarsten Wiese 		if (unlikely(l == 0 || id[p].status)) {
463030a07e4SKarsten Wiese 			snd_printk(KERN_WARNING "underrun, status=%u\n",
464030a07e4SKarsten Wiese 				   id[p].status);
465030a07e4SKarsten Wiese 			goto err_out;
466030a07e4SKarsten Wiese 		}
467030a07e4SKarsten Wiese 		s->inpacket_head++;
468030a07e4SKarsten Wiese 		s->inpacket_head %= s->inpackets;
469030a07e4SKarsten Wiese 		if (s->inpacket_split == -1)
470030a07e4SKarsten Wiese 			s->inpacket_split = s->inpacket_head;
471030a07e4SKarsten Wiese 
472030a07e4SKarsten Wiese 		s->inpacket[s->inpacket_head].offset =
473030a07e4SKarsten Wiese 			id[p].offset + (inurb->transfer_buffer - (void *)s);
474030a07e4SKarsten Wiese 		s->inpacket[s->inpacket_head].length = l;
475030a07e4SKarsten Wiese 		if (insize + l > s->period_size &&
476030a07e4SKarsten Wiese 		    s->next_inpacket_split == -1) {
477030a07e4SKarsten Wiese 			s->next_inpacket_split = s->inpacket_head;
478030a07e4SKarsten Wiese 			s->next_inpacket_split_at = s->period_size - insize;
479030a07e4SKarsten Wiese 		}
480030a07e4SKarsten Wiese 		insize += l;
481030a07e4SKarsten Wiese 		urb_size += l;
482030a07e4SKarsten Wiese 	}
483030a07e4SKarsten Wiese 	s->idle_insize += urb_size - s->period_size;
484030a07e4SKarsten Wiese 	if (s->idle_insize < 0) {
485030a07e4SKarsten Wiese 		snd_printk(KERN_WARNING "%i\n",
486030a07e4SKarsten Wiese 			   (s->idle_insize)/(int)s->cfg.frame_size);
487030a07e4SKarsten Wiese 		goto err_out;
488030a07e4SKarsten Wiese 	}
489030a07e4SKarsten Wiese 	s->insize_done += urb_size;
490030a07e4SKarsten Wiese 
491030a07e4SKarsten Wiese 	l = s->idle_outsize;
492030a07e4SKarsten Wiese 	s->outpacket[0].offset = (sk->idle_outurb->transfer_buffer -
493030a07e4SKarsten Wiese 				  sk->write_page) - l;
494030a07e4SKarsten Wiese 
495030a07e4SKarsten Wiese 	if (usb_stream_prepare_playback(sk, inurb) < 0)
496030a07e4SKarsten Wiese 		goto err_out;
497030a07e4SKarsten Wiese 
498030a07e4SKarsten Wiese 	s->outpacket[0].length = sk->idle_outurb->transfer_buffer_length + l;
499030a07e4SKarsten Wiese 	s->outpacket[1].offset = sk->completed_outurb->transfer_buffer -
500030a07e4SKarsten Wiese 		sk->write_page;
501030a07e4SKarsten Wiese 
502030a07e4SKarsten Wiese 	if (submit_urbs(sk, inurb, outurb) < 0)
503030a07e4SKarsten Wiese 		goto err_out;
504030a07e4SKarsten Wiese 
505030a07e4SKarsten Wiese 	loop_back(s);
506030a07e4SKarsten Wiese 	s->periods_done++;
507030a07e4SKarsten Wiese 	wake_up_all(&sk->sleep);
508030a07e4SKarsten Wiese 	return;
509030a07e4SKarsten Wiese err_out:
510030a07e4SKarsten Wiese 	s->state = usb_stream_xrun;
511030a07e4SKarsten Wiese 	wake_up_all(&sk->sleep);
512030a07e4SKarsten Wiese }
513030a07e4SKarsten Wiese 
i_capture_idle(struct urb * urb)514030a07e4SKarsten Wiese static void i_capture_idle(struct urb *urb)
515030a07e4SKarsten Wiese {
516030a07e4SKarsten Wiese 	struct usb_stream_kernel *sk = urb->context;
5174c0a58efSTakashi Iwai 
518030a07e4SKarsten Wiese 	if (balance_capture(sk, urb))
519030a07e4SKarsten Wiese 		stream_idle(sk, urb, sk->i_urb);
520030a07e4SKarsten Wiese }
521030a07e4SKarsten Wiese 
i_playback_idle(struct urb * urb)522030a07e4SKarsten Wiese static void i_playback_idle(struct urb *urb)
523030a07e4SKarsten Wiese {
524030a07e4SKarsten Wiese 	struct usb_stream_kernel *sk = urb->context;
5254c0a58efSTakashi Iwai 
526030a07e4SKarsten Wiese 	if (balance_playback(sk, urb))
527030a07e4SKarsten Wiese 		stream_idle(sk, sk->i_urb, urb);
528030a07e4SKarsten Wiese }
529030a07e4SKarsten Wiese 
stream_start(struct usb_stream_kernel * sk,struct urb * inurb,struct urb * outurb)530030a07e4SKarsten Wiese static void stream_start(struct usb_stream_kernel *sk,
531030a07e4SKarsten Wiese 			 struct urb *inurb, struct urb *outurb)
532030a07e4SKarsten Wiese {
533030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
5344c0a58efSTakashi Iwai 
535030a07e4SKarsten Wiese 	if (s->state >= usb_stream_sync1) {
536030a07e4SKarsten Wiese 		int l, p, max_diff, max_diff_0;
537030a07e4SKarsten Wiese 		int urb_size = 0;
538a829dd5bSTakashi Iwai 		unsigned int frames_per_packet, min_frames = 0;
5394c0a58efSTakashi Iwai 
540030a07e4SKarsten Wiese 		frames_per_packet = (s->period_size - s->idle_insize);
541030a07e4SKarsten Wiese 		frames_per_packet <<= 8;
542030a07e4SKarsten Wiese 		frames_per_packet /=
543030a07e4SKarsten Wiese 			s->cfg.frame_size * inurb->number_of_packets;
544030a07e4SKarsten Wiese 		frames_per_packet++;
545030a07e4SKarsten Wiese 
546030a07e4SKarsten Wiese 		max_diff_0 = s->cfg.frame_size;
547030a07e4SKarsten Wiese 		if (s->cfg.period_frames >= 256)
548030a07e4SKarsten Wiese 			max_diff_0 <<= 1;
549030a07e4SKarsten Wiese 		if (s->cfg.period_frames >= 1024)
550030a07e4SKarsten Wiese 			max_diff_0 <<= 1;
551030a07e4SKarsten Wiese 		max_diff = max_diff_0;
552030a07e4SKarsten Wiese 		for (p = 0; p < inurb->number_of_packets; ++p) {
553030a07e4SKarsten Wiese 			int diff;
5544c0a58efSTakashi Iwai 
555030a07e4SKarsten Wiese 			l = inurb->iso_frame_desc[p].actual_length;
556030a07e4SKarsten Wiese 			urb_size += l;
557030a07e4SKarsten Wiese 
558030a07e4SKarsten Wiese 			min_frames += frames_per_packet;
559030a07e4SKarsten Wiese 			diff = urb_size -
560030a07e4SKarsten Wiese 				(min_frames >> 8) * s->cfg.frame_size;
561030a07e4SKarsten Wiese 			if (diff < max_diff) {
562030a07e4SKarsten Wiese 				snd_printdd(KERN_DEBUG "%i %i %i %i\n",
563030a07e4SKarsten Wiese 					    s->insize_done,
564030a07e4SKarsten Wiese 					    urb_size / (int)s->cfg.frame_size,
565030a07e4SKarsten Wiese 					    inurb->number_of_packets, diff);
566030a07e4SKarsten Wiese 				max_diff = diff;
567030a07e4SKarsten Wiese 			}
568030a07e4SKarsten Wiese 		}
569030a07e4SKarsten Wiese 		s->idle_insize -= max_diff - max_diff_0;
570030a07e4SKarsten Wiese 		s->idle_insize += urb_size - s->period_size;
571030a07e4SKarsten Wiese 		if (s->idle_insize < 0) {
57254530bdeSTakashi Iwai 			snd_printk(KERN_WARNING "%i %i %i\n",
573030a07e4SKarsten Wiese 				   s->idle_insize, urb_size, s->period_size);
574030a07e4SKarsten Wiese 			return;
575030a07e4SKarsten Wiese 		} else if (s->idle_insize == 0) {
576030a07e4SKarsten Wiese 			s->next_inpacket_split =
577030a07e4SKarsten Wiese 				(s->inpacket_head + 1) % s->inpackets;
578030a07e4SKarsten Wiese 			s->next_inpacket_split_at = 0;
579030a07e4SKarsten Wiese 		} else {
580a829dd5bSTakashi Iwai 			unsigned int split = s->inpacket_head;
5814c0a58efSTakashi Iwai 
582030a07e4SKarsten Wiese 			l = s->idle_insize;
583030a07e4SKarsten Wiese 			while (l > s->inpacket[split].length) {
584030a07e4SKarsten Wiese 				l -= s->inpacket[split].length;
585030a07e4SKarsten Wiese 				if (split == 0)
586030a07e4SKarsten Wiese 					split = s->inpackets - 1;
587030a07e4SKarsten Wiese 				else
588030a07e4SKarsten Wiese 					split--;
589030a07e4SKarsten Wiese 			}
590030a07e4SKarsten Wiese 			s->next_inpacket_split = split;
591030a07e4SKarsten Wiese 			s->next_inpacket_split_at =
592030a07e4SKarsten Wiese 				s->inpacket[split].length - l;
593030a07e4SKarsten Wiese 		}
594030a07e4SKarsten Wiese 
595030a07e4SKarsten Wiese 		s->insize_done += urb_size;
596030a07e4SKarsten Wiese 
597030a07e4SKarsten Wiese 		if (usb_stream_prepare_playback(sk, inurb) < 0)
598030a07e4SKarsten Wiese 			return;
599030a07e4SKarsten Wiese 
600030a07e4SKarsten Wiese 	} else
601030a07e4SKarsten Wiese 		playback_prep_freqn(sk, sk->idle_outurb);
602030a07e4SKarsten Wiese 
603030a07e4SKarsten Wiese 	if (submit_urbs(sk, inurb, outurb) < 0)
604030a07e4SKarsten Wiese 		return;
605030a07e4SKarsten Wiese 
606030a07e4SKarsten Wiese 	if (s->state == usb_stream_sync1 && s->insize_done > 360000) {
607030a07e4SKarsten Wiese 		/* just guesswork                            ^^^^^^ */
608030a07e4SKarsten Wiese 		s->state = usb_stream_ready;
609030a07e4SKarsten Wiese 		subs_set_complete(sk->inurb, i_capture_idle);
610030a07e4SKarsten Wiese 		subs_set_complete(sk->outurb, i_playback_idle);
611030a07e4SKarsten Wiese 	}
612030a07e4SKarsten Wiese }
613030a07e4SKarsten Wiese 
i_capture_start(struct urb * urb)614030a07e4SKarsten Wiese static void i_capture_start(struct urb *urb)
615030a07e4SKarsten Wiese {
616030a07e4SKarsten Wiese 	struct usb_iso_packet_descriptor *id = urb->iso_frame_desc;
617030a07e4SKarsten Wiese 	struct usb_stream_kernel *sk = urb->context;
618030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
619030a07e4SKarsten Wiese 	int p;
620030a07e4SKarsten Wiese 	int empty = 0;
621030a07e4SKarsten Wiese 
622030a07e4SKarsten Wiese 	if (urb->status) {
623030a07e4SKarsten Wiese 		snd_printk(KERN_WARNING "status=%i\n", urb->status);
624030a07e4SKarsten Wiese 		return;
625030a07e4SKarsten Wiese 	}
626030a07e4SKarsten Wiese 
627030a07e4SKarsten Wiese 	for (p = 0; p < urb->number_of_packets; ++p) {
628030a07e4SKarsten Wiese 		int l = id[p].actual_length;
6294c0a58efSTakashi Iwai 
630030a07e4SKarsten Wiese 		if (l < s->cfg.frame_size) {
631030a07e4SKarsten Wiese 			++empty;
632030a07e4SKarsten Wiese 			if (s->state >= usb_stream_sync0) {
633030a07e4SKarsten Wiese 				snd_printk(KERN_WARNING "%i\n", l);
634030a07e4SKarsten Wiese 				return;
635030a07e4SKarsten Wiese 			}
636030a07e4SKarsten Wiese 		}
637030a07e4SKarsten Wiese 		s->inpacket_head++;
638030a07e4SKarsten Wiese 		s->inpacket_head %= s->inpackets;
639030a07e4SKarsten Wiese 		s->inpacket[s->inpacket_head].offset =
640030a07e4SKarsten Wiese 			id[p].offset + (urb->transfer_buffer - (void *)s);
641030a07e4SKarsten Wiese 		s->inpacket[s->inpacket_head].length = l;
642030a07e4SKarsten Wiese 	}
643030a07e4SKarsten Wiese #ifdef SHOW_EMPTY
644030a07e4SKarsten Wiese 	if (empty) {
645030a07e4SKarsten Wiese 		printk(KERN_DEBUG"%s:%i: %i", __func__, __LINE__,
646030a07e4SKarsten Wiese 		       urb->iso_frame_desc[0].actual_length);
647030a07e4SKarsten Wiese 		for (pack = 1; pack < urb->number_of_packets; ++pack) {
648030a07e4SKarsten Wiese 			int l = urb->iso_frame_desc[pack].actual_length;
6494c0a58efSTakashi Iwai 
65010304d71STakashi Iwai 			printk(KERN_CONT " %i", l);
651030a07e4SKarsten Wiese 		}
65210304d71STakashi Iwai 		printk(KERN_CONT "\n");
653030a07e4SKarsten Wiese 	}
654030a07e4SKarsten Wiese #endif
655030a07e4SKarsten Wiese 	if (!empty && s->state < usb_stream_sync1)
656030a07e4SKarsten Wiese 		++s->state;
657030a07e4SKarsten Wiese 
658030a07e4SKarsten Wiese 	if (balance_capture(sk, urb))
659030a07e4SKarsten Wiese 		stream_start(sk, urb, sk->i_urb);
660030a07e4SKarsten Wiese }
661030a07e4SKarsten Wiese 
i_playback_start(struct urb * urb)662030a07e4SKarsten Wiese static void i_playback_start(struct urb *urb)
663030a07e4SKarsten Wiese {
664030a07e4SKarsten Wiese 	struct usb_stream_kernel *sk = urb->context;
6654c0a58efSTakashi Iwai 
666030a07e4SKarsten Wiese 	if (balance_playback(sk, urb))
667030a07e4SKarsten Wiese 		stream_start(sk, sk->i_urb, urb);
668030a07e4SKarsten Wiese }
669030a07e4SKarsten Wiese 
usb_stream_start(struct usb_stream_kernel * sk)670030a07e4SKarsten Wiese int usb_stream_start(struct usb_stream_kernel *sk)
671030a07e4SKarsten Wiese {
672030a07e4SKarsten Wiese 	struct usb_stream *s = sk->s;
673030a07e4SKarsten Wiese 	int frame = 0, iters = 0;
674030a07e4SKarsten Wiese 	int u, err;
675030a07e4SKarsten Wiese 	int try = 0;
676030a07e4SKarsten Wiese 
677030a07e4SKarsten Wiese 	if (s->state != usb_stream_stopped)
678030a07e4SKarsten Wiese 		return -EAGAIN;
679030a07e4SKarsten Wiese 
680030a07e4SKarsten Wiese 	subs_set_complete(sk->inurb, i_capture_start);
681030a07e4SKarsten Wiese 	subs_set_complete(sk->outurb, i_playback_start);
682030a07e4SKarsten Wiese 	memset(sk->write_page, 0, s->write_size);
683030a07e4SKarsten Wiese dotry:
684030a07e4SKarsten Wiese 	s->insize_done = 0;
685030a07e4SKarsten Wiese 	s->idle_insize = 0;
686030a07e4SKarsten Wiese 	s->idle_outsize = 0;
687030a07e4SKarsten Wiese 	s->sync_packet = -1;
688030a07e4SKarsten Wiese 	s->inpacket_head = -1;
689030a07e4SKarsten Wiese 	sk->iso_frame_balance = 0;
690030a07e4SKarsten Wiese 	++try;
691030a07e4SKarsten Wiese 	for (u = 0; u < 2; u++) {
692030a07e4SKarsten Wiese 		struct urb *inurb = sk->inurb[u];
693030a07e4SKarsten Wiese 		struct urb *outurb = sk->outurb[u];
6944c0a58efSTakashi Iwai 
695030a07e4SKarsten Wiese 		playback_prep_freqn(sk, outurb);
696030a07e4SKarsten Wiese 		inurb->number_of_packets = outurb->number_of_packets;
697030a07e4SKarsten Wiese 		inurb->transfer_buffer_length =
698030a07e4SKarsten Wiese 			inurb->number_of_packets *
699030a07e4SKarsten Wiese 			inurb->iso_frame_desc[0].length;
700d0f3a2ebSKarsten Wiese 
701030a07e4SKarsten Wiese 		if (u == 0) {
702030a07e4SKarsten Wiese 			int now;
703030a07e4SKarsten Wiese 			struct usb_device *dev = inurb->dev;
7044c0a58efSTakashi Iwai 
705030a07e4SKarsten Wiese 			frame = usb_get_current_frame_number(dev);
706030a07e4SKarsten Wiese 			do {
707030a07e4SKarsten Wiese 				now = usb_get_current_frame_number(dev);
708030a07e4SKarsten Wiese 				++iters;
709030a07e4SKarsten Wiese 			} while (now > -1 && now == frame);
710030a07e4SKarsten Wiese 		}
711030a07e4SKarsten Wiese 		err = usb_submit_urb(inurb, GFP_ATOMIC);
712030a07e4SKarsten Wiese 		if (err < 0) {
7134c0a58efSTakashi Iwai 			snd_printk(KERN_ERR
7144c0a58efSTakashi Iwai 				   "usb_submit_urb(sk->inurb[%i]) returned %i\n",
7154c0a58efSTakashi Iwai 				   u, err);
716030a07e4SKarsten Wiese 			return err;
717030a07e4SKarsten Wiese 		}
718030a07e4SKarsten Wiese 		err = usb_submit_urb(outurb, GFP_ATOMIC);
719030a07e4SKarsten Wiese 		if (err < 0) {
7204c0a58efSTakashi Iwai 			snd_printk(KERN_ERR
7214c0a58efSTakashi Iwai 				   "usb_submit_urb(sk->outurb[%i]) returned %i\n",
7224c0a58efSTakashi Iwai 				   u, err);
723030a07e4SKarsten Wiese 			return err;
724030a07e4SKarsten Wiese 		}
725d0f3a2ebSKarsten Wiese 
726030a07e4SKarsten Wiese 		if (inurb->start_frame != outurb->start_frame) {
727030a07e4SKarsten Wiese 			snd_printd(KERN_DEBUG
728030a07e4SKarsten Wiese 				   "u[%i] start_frames differ in:%u out:%u\n",
729030a07e4SKarsten Wiese 				   u, inurb->start_frame, outurb->start_frame);
730030a07e4SKarsten Wiese 			goto check_retry;
731030a07e4SKarsten Wiese 		}
732030a07e4SKarsten Wiese 	}
733030a07e4SKarsten Wiese 	snd_printdd(KERN_DEBUG "%i %i\n", frame, iters);
734030a07e4SKarsten Wiese 	try = 0;
735030a07e4SKarsten Wiese check_retry:
736030a07e4SKarsten Wiese 	if (try) {
737030a07e4SKarsten Wiese 		usb_stream_stop(sk);
738030a07e4SKarsten Wiese 		if (try < 5) {
739030a07e4SKarsten Wiese 			msleep(1500);
740030a07e4SKarsten Wiese 			snd_printd(KERN_DEBUG "goto dotry;\n");
741030a07e4SKarsten Wiese 			goto dotry;
742030a07e4SKarsten Wiese 		}
7434c0a58efSTakashi Iwai 		snd_printk(KERN_WARNING
7444c0a58efSTakashi Iwai 			   "couldn't start all urbs on the same start_frame.\n");
745030a07e4SKarsten Wiese 		return -EFAULT;
746030a07e4SKarsten Wiese 	}
747030a07e4SKarsten Wiese 
748030a07e4SKarsten Wiese 	sk->idle_inurb = sk->inurb[USB_STREAM_NURBS - 2];
749030a07e4SKarsten Wiese 	sk->idle_outurb = sk->outurb[USB_STREAM_NURBS - 2];
750030a07e4SKarsten Wiese 	sk->completed_inurb = sk->inurb[USB_STREAM_NURBS - 1];
751030a07e4SKarsten Wiese 	sk->completed_outurb = sk->outurb[USB_STREAM_NURBS - 1];
752030a07e4SKarsten Wiese 
753030a07e4SKarsten Wiese /* wait, check */
754030a07e4SKarsten Wiese 	{
755030a07e4SKarsten Wiese 		int wait_ms = 3000;
7564c0a58efSTakashi Iwai 
757030a07e4SKarsten Wiese 		while (s->state != usb_stream_ready && wait_ms > 0) {
758030a07e4SKarsten Wiese 			snd_printdd(KERN_DEBUG "%i\n", s->state);
759030a07e4SKarsten Wiese 			msleep(200);
760030a07e4SKarsten Wiese 			wait_ms -= 200;
761030a07e4SKarsten Wiese 		}
762030a07e4SKarsten Wiese 	}
763030a07e4SKarsten Wiese 
764030a07e4SKarsten Wiese 	return s->state == usb_stream_ready ? 0 : -EFAULT;
765030a07e4SKarsten Wiese }
766030a07e4SKarsten Wiese 
767030a07e4SKarsten Wiese 
768030a07e4SKarsten Wiese /*                             stop                                   */
769030a07e4SKarsten Wiese 
usb_stream_stop(struct usb_stream_kernel * sk)770030a07e4SKarsten Wiese void usb_stream_stop(struct usb_stream_kernel *sk)
771030a07e4SKarsten Wiese {
772030a07e4SKarsten Wiese 	int u;
7734c0a58efSTakashi Iwai 
774030a07e4SKarsten Wiese 	if (!sk->s)
775030a07e4SKarsten Wiese 		return;
776030a07e4SKarsten Wiese 	for (u = 0; u < USB_STREAM_NURBS; ++u) {
777030a07e4SKarsten Wiese 		usb_kill_urb(sk->inurb[u]);
778030a07e4SKarsten Wiese 		usb_kill_urb(sk->outurb[u]);
779030a07e4SKarsten Wiese 	}
780030a07e4SKarsten Wiese 	sk->s->state = usb_stream_stopped;
781030a07e4SKarsten Wiese 	msleep(400);
782030a07e4SKarsten Wiese }
783