xref: /openbmc/linux/sound/usb/usx2y/usx2yhwdeppcm.c (revision 12eb4683)
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15  */
16 
17 /* USX2Y "rawusb" aka hwdep_pcm implementation
18 
19  Its usb's unableness to atomically handle power of 2 period sized data chuncs
20  at standard samplerates,
21  what led to this part of the usx2y module:
22  It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
23  The pair uses a hardware dependent alsa-device for mmaped pcm transport.
24  Advantage achieved:
25          The usb_hc moves pcm data from/into memory via DMA.
26          That memory is mmaped by jack's usx2y driver.
27          Jack's usx2y driver is the first/last to read/write pcm data.
28          Read/write is a combination of power of 2 period shaping and
29          float/int conversation.
30          Compared to mainline alsa/jack we leave out power of 2 period shaping inside
31          snd-usb-usx2y which needs memcpy() and additional buffers.
32          As a side effect possible unwanted pcm-data coruption resulting of
33          standard alsa's snd-usb-usx2y period shaping scheme falls away.
34          Result is sane jack operation at buffering schemes down to 128frames,
35          2 periods.
36          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
37          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
38          2periods works but is useless cause of crackling).
39 
40  This is a first "proof of concept" implementation.
41  Later, functionalities should migrate to more appropriate places:
42  Userland:
43  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
44  - alsa-lib could provide power of 2 period sized shaping combined with int/float
45    conversation.
46    Currently the usx2y jack driver provides above 2 services.
47  Kernel:
48  - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
49    devices can use it.
50    Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y.
51 */
52 
53 #include <linux/delay.h>
54 #include <linux/gfp.h>
55 #include "usbusx2yaudio.c"
56 
57 #if defined(USX2Y_NRPACKS_VARIABLE) || USX2Y_NRPACKS == 1
58 
59 #include <sound/hwdep.h>
60 
61 
62 static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
63 {
64 	struct urb	*urb = subs->completed_urb;
65 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
66 	int 		i, lens = 0, hwptr_done = subs->hwptr_done;
67 	struct usX2Ydev	*usX2Y = subs->usX2Y;
68 	if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
69 		int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
70 		if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
71 			head = 0;
72 		usX2Y->hwdep_pcm_shm->capture_iso_start = head;
73 		snd_printdd("cap start %i\n", head);
74 	}
75 	for (i = 0; i < nr_of_packs(); i++) {
76 		if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
77 			snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
78 			return urb->iso_frame_desc[i].status;
79 		}
80 		lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
81 	}
82 	if ((hwptr_done += lens) >= runtime->buffer_size)
83 		hwptr_done -= runtime->buffer_size;
84 	subs->hwptr_done = hwptr_done;
85 	subs->transfer_done += lens;
86 	/* update the pointer, call callback if necessary */
87 	if (subs->transfer_done >= runtime->period_size) {
88 		subs->transfer_done -= runtime->period_size;
89 		snd_pcm_period_elapsed(subs->pcm_substream);
90 	}
91 	return 0;
92 }
93 
94 static inline int usX2Y_iso_frames_per_buffer(struct snd_pcm_runtime *runtime,
95 					      struct usX2Ydev * usX2Y)
96 {
97 	return (runtime->buffer_size * 1000) / usX2Y->rate + 1;	//FIXME: so far only correct period_size == 2^x ?
98 }
99 
100 /*
101  * prepare urb for playback data pipe
102  *
103  * we copy the data directly from the pcm buffer.
104  * the current position to be copied is held in hwptr field.
105  * since a urb can handle only a single linear buffer, if the total
106  * transferred area overflows the buffer boundary, we cannot send
107  * it directly from the buffer.  thus the data is once copied to
108  * a temporary buffer and urb points to that.
109  */
110 static int usX2Y_hwdep_urb_play_prepare(struct snd_usX2Y_substream *subs,
111 					struct urb *urb)
112 {
113 	int count, counts, pack;
114 	struct usX2Ydev *usX2Y = subs->usX2Y;
115 	struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
116 	struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
117 
118 	if (0 > shm->playback_iso_start) {
119 		shm->playback_iso_start = shm->captured_iso_head -
120 			usX2Y_iso_frames_per_buffer(runtime, usX2Y);
121 		if (0 > shm->playback_iso_start)
122 			shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
123 		shm->playback_iso_head = shm->playback_iso_start;
124 	}
125 
126 	count = 0;
127 	for (pack = 0; pack < nr_of_packs(); pack++) {
128 		/* calculate the size of a packet */
129 		counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
130 		if (counts < 43 || counts > 50) {
131 			snd_printk(KERN_ERR "should not be here with counts=%i\n", counts);
132 			return -EPIPE;
133 		}
134 		/* set up descriptor */
135 		urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
136 		urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
137 		if (atomic_read(&subs->state) != state_RUNNING)
138 			memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
139 			       urb->iso_frame_desc[pack].length);
140 		if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
141 			shm->playback_iso_head = 0;
142 		count += counts;
143 	}
144 	urb->transfer_buffer_length = count * usX2Y->stride;
145 	return 0;
146 }
147 
148 
149 static inline void usX2Y_usbpcm_urb_capt_iso_advance(struct snd_usX2Y_substream *subs,
150 						     struct urb *urb)
151 {
152 	int pack;
153 	for (pack = 0; pack < nr_of_packs(); ++pack) {
154 		struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
155 		if (NULL != subs) {
156 			struct snd_usX2Y_hwdep_pcm_shm *shm = subs->usX2Y->hwdep_pcm_shm;
157 			int head = shm->captured_iso_head + 1;
158 			if (head >= ARRAY_SIZE(shm->captured_iso))
159 				head = 0;
160 			shm->captured_iso[head].frame = urb->start_frame + pack;
161 			shm->captured_iso[head].offset = desc->offset;
162 			shm->captured_iso[head].length = desc->actual_length;
163 			shm->captured_iso_head = head;
164 			shm->captured_iso_frames++;
165 		}
166 		if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
167 		    desc->length >= SSS)
168 			desc->offset -= (SSS - desc->length);
169 	}
170 }
171 
172 static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *capsubs,
173 						 struct snd_usX2Y_substream *capsubs2,
174 						 struct snd_usX2Y_substream *playbacksubs,
175 						 int frame)
176 {
177 	int err, state;
178 	struct urb *urb = playbacksubs->completed_urb;
179 
180 	state = atomic_read(&playbacksubs->state);
181 	if (NULL != urb) {
182 		if (state == state_RUNNING)
183 			usX2Y_urb_play_retire(playbacksubs, urb);
184 		else if (state >= state_PRERUNNING)
185 			atomic_inc(&playbacksubs->state);
186 	} else {
187 		switch (state) {
188 		case state_STARTING1:
189 			urb = playbacksubs->urb[0];
190 			atomic_inc(&playbacksubs->state);
191 			break;
192 		case state_STARTING2:
193 			urb = playbacksubs->urb[1];
194 			atomic_inc(&playbacksubs->state);
195 			break;
196 		}
197 	}
198 	if (urb) {
199 		if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
200 		    (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
201 			return err;
202 		}
203 	}
204 
205 	playbacksubs->completed_urb = NULL;
206 
207 	state = atomic_read(&capsubs->state);
208 	if (state >= state_PREPARED) {
209 		if (state == state_RUNNING) {
210 			if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
211 				return err;
212 		} else if (state >= state_PRERUNNING)
213 			atomic_inc(&capsubs->state);
214 		usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
215 		if (NULL != capsubs2)
216 			usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
217 		if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
218 			return err;
219 		if (NULL != capsubs2)
220 			if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
221 				return err;
222 	}
223 	capsubs->completed_urb = NULL;
224 	if (NULL != capsubs2)
225 		capsubs2->completed_urb = NULL;
226 	return 0;
227 }
228 
229 
230 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
231 {
232 	struct snd_usX2Y_substream *subs = urb->context;
233 	struct usX2Ydev *usX2Y = subs->usX2Y;
234 	struct snd_usX2Y_substream *capsubs, *capsubs2, *playbacksubs;
235 
236 	if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
237 		snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n",
238 			    usb_get_current_frame_number(usX2Y->dev),
239 			    subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
240 			    urb->status, urb->start_frame);
241 		return;
242 	}
243 	if (unlikely(urb->status)) {
244 		usX2Y_error_urb_status(usX2Y, subs, urb);
245 		return;
246 	}
247 
248 	subs->completed_urb = urb;
249 	capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
250 	capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
251 	playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
252 	if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
253 	    (NULL == capsubs2 || capsubs2->completed_urb) &&
254 	    (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
255 		if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
256 			usX2Y->wait_iso_frame += nr_of_packs();
257 		else {
258 			snd_printdd("\n");
259 			usX2Y_clients_stop(usX2Y);
260 		}
261 	}
262 }
263 
264 
265 static void usX2Y_hwdep_urb_release(struct urb **urb)
266 {
267 	usb_kill_urb(*urb);
268 	usb_free_urb(*urb);
269 	*urb = NULL;
270 }
271 
272 /*
273  * release a substream
274  */
275 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
276 {
277 	int i;
278 	snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
279 	for (i = 0; i < NRURBS; i++)
280 		usX2Y_hwdep_urb_release(subs->urb + i);
281 }
282 
283 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
284 {
285 	usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
286 	usX2Y->prepare_subs = NULL;
287 }
288 
289 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
290 {
291 	struct snd_usX2Y_substream *subs = urb->context;
292 	struct usX2Ydev *usX2Y = subs->usX2Y;
293 	struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
294 	if (NULL != prepare_subs &&
295 	    urb->start_frame == prepare_subs->urb[0]->start_frame) {
296 		atomic_inc(&prepare_subs->state);
297 		if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
298 			struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
299 			if (cap_subs2 != NULL)
300 				atomic_inc(&cap_subs2->state);
301 		}
302 		usX2Y_usbpcm_subs_startup_finish(usX2Y);
303 		wake_up(&usX2Y->prepare_wait_queue);
304 	}
305 
306 	i_usX2Y_usbpcm_urb_complete(urb);
307 }
308 
309 /*
310  * initialize a substream's urbs
311  */
312 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
313 {
314 	int i;
315 	unsigned int pipe;
316 	int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
317 	struct usb_device *dev = subs->usX2Y->dev;
318 
319 	pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
320 			usb_rcvisocpipe(dev, subs->endpoint);
321 	subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
322 	if (!subs->maxpacksize)
323 		return -EINVAL;
324 
325 	/* allocate and initialize data urbs */
326 	for (i = 0; i < NRURBS; i++) {
327 		struct urb **purb = subs->urb + i;
328 		if (*purb) {
329 			usb_kill_urb(*purb);
330 			continue;
331 		}
332 		*purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
333 		if (NULL == *purb) {
334 			usX2Y_usbpcm_urbs_release(subs);
335 			return -ENOMEM;
336 		}
337 		(*purb)->transfer_buffer = is_playback ?
338 			subs->usX2Y->hwdep_pcm_shm->playback : (
339 				subs->endpoint == 0x8 ?
340 				subs->usX2Y->hwdep_pcm_shm->capture0x8 :
341 				subs->usX2Y->hwdep_pcm_shm->capture0xA);
342 
343 		(*purb)->dev = dev;
344 		(*purb)->pipe = pipe;
345 		(*purb)->number_of_packets = nr_of_packs();
346 		(*purb)->context = subs;
347 		(*purb)->interval = 1;
348 		(*purb)->complete = i_usX2Y_usbpcm_subs_startup;
349 	}
350 	return 0;
351 }
352 
353 /*
354  * free the buffer
355  */
356 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
357 {
358 	struct snd_pcm_runtime *runtime = substream->runtime;
359 	struct snd_usX2Y_substream *subs = runtime->private_data,
360 		*cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
361 	mutex_lock(&subs->usX2Y->prepare_mutex);
362 	snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
363 
364 	if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
365 		struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
366 		atomic_set(&subs->state, state_STOPPED);
367 		usX2Y_usbpcm_urbs_release(subs);
368 		if (!cap_subs->pcm_substream ||
369 		    !cap_subs->pcm_substream->runtime ||
370 		    !cap_subs->pcm_substream->runtime->status ||
371 		    cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
372 			atomic_set(&cap_subs->state, state_STOPPED);
373 			if (NULL != cap_subs2)
374 				atomic_set(&cap_subs2->state, state_STOPPED);
375 			usX2Y_usbpcm_urbs_release(cap_subs);
376 			if (NULL != cap_subs2)
377 				usX2Y_usbpcm_urbs_release(cap_subs2);
378 		}
379 	} else {
380 		struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
381 		if (atomic_read(&playback_subs->state) < state_PREPARED) {
382 			atomic_set(&subs->state, state_STOPPED);
383 			if (NULL != cap_subs2)
384 				atomic_set(&cap_subs2->state, state_STOPPED);
385 			usX2Y_usbpcm_urbs_release(subs);
386 			if (NULL != cap_subs2)
387 				usX2Y_usbpcm_urbs_release(cap_subs2);
388 		}
389 	}
390 	mutex_unlock(&subs->usX2Y->prepare_mutex);
391 	return snd_pcm_lib_free_pages(substream);
392 }
393 
394 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
395 {
396 	struct usX2Ydev * usX2Y = subs->usX2Y;
397 	usX2Y->prepare_subs = subs;
398 	subs->urb[0]->start_frame = -1;
399 	smp_wmb();	// Make sure above modifications are seen by i_usX2Y_subs_startup()
400 	usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
401 }
402 
403 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
404 {
405 	int	p, u, err,
406 		stream = subs->pcm_substream->stream;
407 	struct usX2Ydev *usX2Y = subs->usX2Y;
408 
409 	if (SNDRV_PCM_STREAM_CAPTURE == stream) {
410 		usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
411 		usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
412 	}
413 
414 	for (p = 0; 3 >= (stream + p); p += 2) {
415 		struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
416 		if (subs != NULL) {
417 			if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
418 				return err;
419 			subs->completed_urb = NULL;
420 		}
421 	}
422 
423 	for (p = 0; p < 4; p++) {
424 		struct snd_usX2Y_substream *subs = usX2Y->subs[p];
425 		if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
426 			goto start;
427 	}
428 
429  start:
430 	usX2Y_usbpcm_subs_startup(subs);
431 	for (u = 0; u < NRURBS; u++) {
432 		for (p = 0; 3 >= (stream + p); p += 2) {
433 			struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
434 			if (subs != NULL) {
435 				struct urb *urb = subs->urb[u];
436 				if (usb_pipein(urb->pipe)) {
437 					unsigned long pack;
438 					if (0 == u)
439 						atomic_set(&subs->state, state_STARTING3);
440 					urb->dev = usX2Y->dev;
441 					for (pack = 0; pack < nr_of_packs(); pack++) {
442 						urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
443 						urb->iso_frame_desc[pack].length = subs->maxpacksize;
444 					}
445 					urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs();
446 					if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
447 						snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
448 						err = -EPIPE;
449 						goto cleanup;
450 					}  else {
451 						snd_printdd("%i\n", urb->start_frame);
452 						if (u == 0)
453 							usX2Y->wait_iso_frame = urb->start_frame;
454 					}
455 					urb->transfer_flags = 0;
456 				} else {
457 					atomic_set(&subs->state, state_STARTING1);
458 					break;
459 				}
460 			}
461 		}
462 	}
463 	err = 0;
464 	wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
465 	if (atomic_read(&subs->state) != state_PREPARED)
466 		err = -EPIPE;
467 
468  cleanup:
469 	if (err) {
470 		usX2Y_subs_startup_finish(usX2Y);	// Call it now
471 		usX2Y_clients_stop(usX2Y);		// something is completely wroong > stop evrything
472 	}
473 	return err;
474 }
475 
476 /*
477  * prepare callback
478  *
479  * set format and initialize urbs
480  */
481 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
482 {
483 	struct snd_pcm_runtime *runtime = substream->runtime;
484 	struct snd_usX2Y_substream *subs = runtime->private_data;
485 	struct usX2Ydev *usX2Y = subs->usX2Y;
486 	struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
487 	int err = 0;
488 	snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
489 
490 	if (NULL == usX2Y->hwdep_pcm_shm) {
491 		if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
492 			return -ENOMEM;
493 		memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
494 	}
495 
496 	mutex_lock(&usX2Y->prepare_mutex);
497 	usX2Y_subs_prepare(subs);
498 // Start hardware streams
499 // SyncStream first....
500 	if (atomic_read(&capsubs->state) < state_PREPARED) {
501 		if (usX2Y->format != runtime->format)
502 			if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
503 				goto up_prepare_mutex;
504 		if (usX2Y->rate != runtime->rate)
505 			if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
506 				goto up_prepare_mutex;
507 		snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
508 			    "self" : "playpipe");
509 		if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
510 			goto up_prepare_mutex;
511 	}
512 
513 	if (subs != capsubs) {
514 		usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
515 		if (atomic_read(&subs->state) < state_PREPARED) {
516 			while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
517 			       usX2Y->hwdep_pcm_shm->captured_iso_frames) {
518 				snd_printdd("Wait: iso_frames_per_buffer=%i,"
519 					    "captured_iso_frames=%i\n",
520 					    usX2Y_iso_frames_per_buffer(runtime, usX2Y),
521 					    usX2Y->hwdep_pcm_shm->captured_iso_frames);
522 				if (msleep_interruptible(10)) {
523 					err = -ERESTARTSYS;
524 					goto up_prepare_mutex;
525 				}
526 			}
527 			if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
528 				goto up_prepare_mutex;
529 		}
530 		snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
531 			    usX2Y_iso_frames_per_buffer(runtime, usX2Y),
532 			    usX2Y->hwdep_pcm_shm->captured_iso_frames);
533 	} else
534 		usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
535 
536  up_prepare_mutex:
537 	mutex_unlock(&usX2Y->prepare_mutex);
538 	return err;
539 }
540 
541 static struct snd_pcm_hardware snd_usX2Y_4c =
542 {
543 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
544 				 SNDRV_PCM_INFO_BLOCK_TRANSFER |
545 				 SNDRV_PCM_INFO_MMAP_VALID),
546 	.formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
547 	.rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
548 	.rate_min =                44100,
549 	.rate_max =                48000,
550 	.channels_min =            2,
551 	.channels_max =            4,
552 	.buffer_bytes_max =	(2*128*1024),
553 	.period_bytes_min =	64,
554 	.period_bytes_max =	(128*1024),
555 	.periods_min =		2,
556 	.periods_max =		1024,
557 	.fifo_size =              0
558 };
559 
560 
561 
562 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
563 {
564 	struct snd_usX2Y_substream	*subs = ((struct snd_usX2Y_substream **)
565 					 snd_pcm_substream_chip(substream))[substream->stream];
566 	struct snd_pcm_runtime	*runtime = substream->runtime;
567 
568 	if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
569 		return -EBUSY;
570 
571 	runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
572 		(subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
573 	runtime->private_data = subs;
574 	subs->pcm_substream = substream;
575 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
576 	return 0;
577 }
578 
579 
580 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
581 {
582 	struct snd_pcm_runtime *runtime = substream->runtime;
583 	struct snd_usX2Y_substream *subs = runtime->private_data;
584 
585 	subs->pcm_substream = NULL;
586 	return 0;
587 }
588 
589 
590 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops =
591 {
592 	.open =		snd_usX2Y_usbpcm_open,
593 	.close =	snd_usX2Y_usbpcm_close,
594 	.ioctl =	snd_pcm_lib_ioctl,
595 	.hw_params =	snd_usX2Y_pcm_hw_params,
596 	.hw_free =	snd_usX2Y_usbpcm_hw_free,
597 	.prepare =	snd_usX2Y_usbpcm_prepare,
598 	.trigger =	snd_usX2Y_pcm_trigger,
599 	.pointer =	snd_usX2Y_pcm_pointer,
600 };
601 
602 
603 static int usX2Y_pcms_lock_check(struct snd_card *card)
604 {
605 	struct list_head *list;
606 	struct snd_device *dev;
607 	struct snd_pcm *pcm;
608 	int err = 0;
609 	list_for_each(list, &card->devices) {
610 		dev = snd_device(list);
611 		if (dev->type != SNDRV_DEV_PCM)
612 			continue;
613 		pcm = dev->device_data;
614 		mutex_lock(&pcm->open_mutex);
615 	}
616 	list_for_each(list, &card->devices) {
617 		int s;
618 		dev = snd_device(list);
619 		if (dev->type != SNDRV_DEV_PCM)
620 			continue;
621 		pcm = dev->device_data;
622 		for (s = 0; s < 2; ++s) {
623 			struct snd_pcm_substream *substream;
624 			substream = pcm->streams[s].substream;
625 			if (substream && SUBSTREAM_BUSY(substream))
626 				err = -EBUSY;
627 		}
628 	}
629 	return err;
630 }
631 
632 
633 static void usX2Y_pcms_unlock(struct snd_card *card)
634 {
635 	struct list_head *list;
636 	struct snd_device *dev;
637 	struct snd_pcm *pcm;
638 	list_for_each(list, &card->devices) {
639 		dev = snd_device(list);
640 		if (dev->type != SNDRV_DEV_PCM)
641 			continue;
642 		pcm = dev->device_data;
643 		mutex_unlock(&pcm->open_mutex);
644 	}
645 }
646 
647 
648 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
649 {
650 	// we need to be the first
651 	struct snd_card *card = hw->card;
652 	int err = usX2Y_pcms_lock_check(card);
653 	if (0 == err)
654 		usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
655 	usX2Y_pcms_unlock(card);
656 	return err;
657 }
658 
659 
660 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
661 {
662 	struct snd_card *card = hw->card;
663 	int err = usX2Y_pcms_lock_check(card);
664 	if (0 == err)
665 		usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
666 	usX2Y_pcms_unlock(card);
667 	return err;
668 }
669 
670 
671 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
672 {
673 }
674 
675 
676 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
677 {
678 }
679 
680 
681 static int snd_usX2Y_hwdep_pcm_vm_fault(struct vm_area_struct *area,
682 					struct vm_fault *vmf)
683 {
684 	unsigned long offset;
685 	void *vaddr;
686 
687 	offset = vmf->pgoff << PAGE_SHIFT;
688 	vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
689 	vmf->page = virt_to_page(vaddr);
690 	get_page(vmf->page);
691 	return 0;
692 }
693 
694 
695 static const struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
696 	.open = snd_usX2Y_hwdep_pcm_vm_open,
697 	.close = snd_usX2Y_hwdep_pcm_vm_close,
698 	.fault = snd_usX2Y_hwdep_pcm_vm_fault,
699 };
700 
701 
702 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
703 {
704 	unsigned long	size = (unsigned long)(area->vm_end - area->vm_start);
705 	struct usX2Ydev	*usX2Y = hw->private_data;
706 
707 	if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
708 		return -EBUSY;
709 
710 	/* if userspace tries to mmap beyond end of our buffer, fail */
711 	if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
712 		snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm));
713 		return -EINVAL;
714 	}
715 
716 	if (!usX2Y->hwdep_pcm_shm) {
717 		return -ENODEV;
718 	}
719 	area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
720 	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
721 	area->vm_private_data = hw->private_data;
722 	return 0;
723 }
724 
725 
726 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
727 {
728 	struct usX2Ydev *usX2Y = hwdep->private_data;
729 	if (NULL != usX2Y->hwdep_pcm_shm)
730 		snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
731 }
732 
733 
734 int usX2Y_hwdep_pcm_new(struct snd_card *card)
735 {
736 	int err;
737 	struct snd_hwdep *hw;
738 	struct snd_pcm *pcm;
739 	struct usb_device *dev = usX2Y(card)->dev;
740 	if (1 != nr_of_packs())
741 		return 0;
742 
743 	if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0)
744 		return err;
745 
746 	hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
747 	hw->private_data = usX2Y(card);
748 	hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
749 	hw->ops.open = snd_usX2Y_hwdep_pcm_open;
750 	hw->ops.release = snd_usX2Y_hwdep_pcm_release;
751 	hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
752 	hw->exclusive = 1;
753 	sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
754 
755 	err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
756 	if (err < 0) {
757 		return err;
758 	}
759 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
760 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
761 
762 	pcm->private_data = usX2Y(card)->subs;
763 	pcm->info_flags = 0;
764 
765 	sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
766 	if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
767 						     SNDRV_DMA_TYPE_CONTINUOUS,
768 						     snd_dma_continuous_data(GFP_KERNEL),
769 						     64*1024, 128*1024)) ||
770 	    0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
771 	    					     SNDRV_DMA_TYPE_CONTINUOUS,
772 	    					     snd_dma_continuous_data(GFP_KERNEL),
773 						     64*1024, 128*1024))) {
774 		return err;
775 	}
776 
777 
778 	return 0;
779 }
780 
781 #else
782 
783 int usX2Y_hwdep_pcm_new(struct snd_card *card)
784 {
785 	return 0;
786 }
787 
788 #endif
789