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